summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--OWNERS_leaudio1
-rw-r--r--TEST_MAPPING179
-rw-r--r--android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java10
-rw-r--r--android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java15
-rw-r--r--android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java8
-rw-r--r--android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml104
-rw-r--r--android/app/Android.bp1
-rw-r--r--android/app/OWNERS1
-rw-r--r--android/app/aidl/android/bluetooth/IBluetooth.aidl11
-rw-r--r--android/app/aidl/android/bluetooth/IBluetoothGatt.aidl9
-rw-r--r--android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl4
-rw-r--r--android/app/jni/com_android_bluetooth_a2dp.cpp102
-rw-r--r--android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp35
-rw-r--r--android/app/jni/com_android_bluetooth_gatt.cpp101
-rw-r--r--android/app/jni/com_android_bluetooth_le_audio.cpp2
-rw-r--r--android/app/src/com/android/bluetooth/BluetoothMethodProxy.java15
-rw-r--r--android/app/src/com/android/bluetooth/Utils.java6
-rw-r--r--android/app/src/com/android/bluetooth/a2dp/A2dpNativeCallback.java95
-rw-r--r--android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java124
-rw-r--r--android/app/src/com/android/bluetooth/a2dp/A2dpService.java47
-rw-r--r--android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java9
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java4
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java29
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java5
-rw-r--r--android/app/src/com/android/bluetooth/bas/BatteryStateMachine.java14
-rw-r--r--android/app/src/com/android/bluetooth/bass_client/BassClientService.java515
-rw-r--r--android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java257
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java1
-rw-r--r--android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java27
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java75
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterProperties.java38
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterService.java123
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterSuspend.java100
-rw-r--r--android/app/src/com/android/bluetooth/btservice/BluetoothHciVendorSpecificNativeInterface.java35
-rw-r--r--android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java156
-rw-r--r--android/app/src/com/android/bluetooth/btservice/Config.java139
-rw-r--r--android/app/src/com/android/bluetooth/btservice/RemoteDevices.java26
-rw-r--r--android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface.java73
-rw-r--r--android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java225
-rw-r--r--android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java13
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java6
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java214
-rw-r--r--android/app/src/com/android/bluetooth/hfp/HeadsetService.java3
-rw-r--r--android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java2
-rw-r--r--android/app/src/com/android/bluetooth/le_audio/LeAudioService.java211
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java37
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternList.java75
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/ScanController.java8
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/ScanManager.java102
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/ScanObjectsFactory.java4
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/ScannerMap.java9
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java15
-rw-r--r--android/app/src/com/android/bluetooth/map/BluetoothMapContent.java2
-rw-r--r--android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java34
-rw-r--r--android/app/src/com/android/bluetooth/map/BluetoothMapConvoListingElement.java1
-rw-r--r--android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java106
-rw-r--r--android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java15
-rw-r--r--android/app/src/com/android/bluetooth/mcp/McpService.java15
-rw-r--r--android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java102
-rw-r--r--android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java43
-rw-r--r--android/app/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java22
-rw-r--r--android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java14
-rw-r--r--android/app/src/com/android/bluetooth/opp/Constants.java8
-rw-r--r--android/app/src/com/android/bluetooth/pbapclient/PbapClientContactsStorage.java152
-rw-r--r--android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java6
-rw-r--r--android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachineOld.java56
-rw-r--r--android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexClient.java5
-rw-r--r--android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientSocket.java5
-rw-r--r--android/app/src/com/android/bluetooth/telephony/BluetoothCall.java4
-rw-r--r--android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java138
-rw-r--r--android/app/src/com/android/bluetooth/vc/VolumeControlService.java273
-rw-r--r--android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java8
-rw-r--r--android/app/tests/unit/Android.bp3
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/FileSystemWriteTest.java27
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/TestUtils.java31
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java25
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java23
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java14
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerListTest.java1
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java49
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java3
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcp/AvrcpTargetServiceTest.java102
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java112
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorageTest.java94
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpItemTest.java30
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipAttachmentFormatTest.java13
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipDatetimeTest.java11
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipEncodingTest.java6
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptorTest.java11
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormatTest.java11
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImagePropertiesTest.java24
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageTest.java10
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformationTest.java192
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java54
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java484
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java111
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java34
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterSuspendTest.java10
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java18
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java23
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java35
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java21
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java100
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/SilenceDeviceManagerTest.java12
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java52
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java280
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java757
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachineTest.java13
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java65
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java92
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java99
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetTestUtils.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java10
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java43
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java6
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_audio/ContentControlIdKeeperTest.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java48
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java19
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/AppScanStatsTest.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternListTest.java74
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java1031
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/TransitionalScanHelperTest.java1
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapContentObserverTest.java326
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java20
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java49
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java38
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceTest.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlGattServiceTest.java106
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlProfileTest.java40
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppReceiverTest.java86
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppSendFileInfoTest.java106
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java3
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferHistoryTest.java13
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java3
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGattTest.java151
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java45
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java282
-rwxr-xr-xandroid/pandora/gen_cov.py4
-rw-r--r--android/pandora/server/Android.bp5
-rw-r--r--android/pandora/server/configs/pts_bot_tests_config.json9
-rw-r--r--android/pandora/server/src/Pbap.kt2
-rw-r--r--android/pandora/test/a2dp/__init__.py0
-rw-r--r--android/pandora/test/a2dp/packets/__init__.py0
-rw-r--r--android/pandora/test/a2dp/packets/avdtp.pdl343
-rw-r--r--android/pandora/test/a2dp/packets/avdtp.py2109
-rw-r--r--android/pandora/test/a2dp_test.py128
-rw-r--r--apex/Android.bp132
-rw-r--r--apex/hiddenapi/OWNERS4
-rw-r--r--apex/key.pem52
-rw-r--r--apex/key/Android.bp16
-rw-r--r--apex/key/com.android.bt.avbpubkeybin0 -> 1032 bytes
-rw-r--r--apex/key/com.android.bt.pem52
-rw-r--r--apex/key/com.android.bt.pk8bin0 -> 2374 bytes
-rw-r--r--apex/key/com.android.bt.x509.pem34
-rw-r--r--apex/manifest.json7
-rw-r--r--flags/Android.bp2
-rw-r--r--flags/BUILD.gn2
-rw-r--r--flags/a2dp.aconfig100
-rw-r--r--flags/asha.aconfig12
-rw-r--r--flags/avrcp.aconfig10
-rw-r--r--flags/bta_dm.aconfig7
-rw-r--r--flags/framework.aconfig10
-rw-r--r--flags/gap.aconfig80
-rw-r--r--flags/gatt.aconfig8
-rw-r--r--flags/leaudio.aconfig66
-rw-r--r--flags/map.aconfig9
-rw-r--r--flags/opp.aconfig17
-rw-r--r--flags/pairing.aconfig30
-rw-r--r--flags/security.aconfig19
-rw-r--r--flags/service_discovery.aconfig10
-rw-r--r--flags/sockets.aconfig10
-rw-r--r--flags/system_service.aconfig20
-rw-r--r--flags/vcp.aconfig10
-rw-r--r--floss/pandora/floss/qa_client.py26
-rw-r--r--framework/Android.bp2
-rw-r--r--framework/api/current.txt18
-rw-r--r--framework/api/system-current.txt21
-rw-r--r--framework/jarjar-rules.txt12
-rw-r--r--framework/java/android/bluetooth/AudioInputControl.java6
-rw-r--r--framework/java/android/bluetooth/BluetoothAdapter.java180
-rw-r--r--framework/java/android/bluetooth/BluetoothCodecType.java18
-rw-r--r--framework/java/android/bluetooth/BluetoothDevice.java120
-rw-r--r--framework/java/android/bluetooth/BluetoothGatt.java97
-rw-r--r--framework/java/android/bluetooth/BluetoothGattServer.java12
-rw-r--r--framework/java/android/bluetooth/BluetoothManager.java2
-rw-r--r--framework/java/android/bluetooth/BluetoothServerSocket.java55
-rw-r--r--framework/java/android/bluetooth/BluetoothSocket.java316
-rw-r--r--framework/java/android/bluetooth/BluetoothSocketException.java27
-rw-r--r--framework/java/android/bluetooth/BluetoothSocketSettings.java414
-rw-r--r--framework/java/android/bluetooth/le/AdvertisingSet.java8
-rw-r--r--framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java22
-rw-r--r--framework/java/android/bluetooth/le/DistanceMeasurementManager.java15
-rw-r--r--framework/java/android/bluetooth/le/DistanceMeasurementResult.java12
-rw-r--r--framework/tests/bumble/Android.bp2
-rw-r--r--framework/tests/bumble/src/android/bluetooth/GattClientTest.java38
-rw-r--r--framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java12
-rw-r--r--framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java13
-rw-r--r--framework/tests/bumble/src/android/bluetooth/LeLegacyAdvertisingTest.java9
-rw-r--r--framework/tests/bumble/src/android/bluetooth/RfcommTest.kt188
-rw-r--r--framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java657
-rw-r--r--framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java9
-rw-r--r--framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java13
-rw-r--r--framework/tests/bumble/src/android/bluetooth/pairing/EncryptionChangeTest.java440
-rw-r--r--framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java108
-rw-r--r--framework/tests/bumble/src/android/bluetooth/service_discovery/LeAudioServiceDiscoveryTest.java4
-rw-r--r--framework/tests/bumble/src/android/bluetooth/service_discovery/ServiceDiscoveryTest.java27
-rw-r--r--framework/tests/unit/Android.bp1
-rw-r--r--framework/tests/unit/src/android/bluetooth/BluetoothDeviceTest.java86
-rw-r--r--framework/tests/util/Android.bp1
-rw-r--r--pandora/interfaces/pandora_experimental/hid.proto12
-rw-r--r--pandora/server/bumble_experimental/hid.py45
-rw-r--r--service/Android.bp25
-rw-r--r--service/src/com/android/server/bluetooth/BluetoothManagerService.java69
-rw-r--r--service/tests/Android.bp1
-rw-r--r--system/Android.bp293
-rw-r--r--system/BUILD.gn1
-rw-r--r--system/OWNERS1
-rw-r--r--system/audio/Android.bp3
-rw-r--r--system/audio/asrc/asrc_resampler.cc1
-rw-r--r--system/audio_bluetooth_hw/Android.bp2
-rw-r--r--system/audio_hal_interface/Android.bp2
-rw-r--r--system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc5
-rw-r--r--system/audio_hal_interface/fuzzer/Android.bp1
-rw-r--r--system/blueberry/facade/common.proto35
-rw-r--r--system/blueberry/facade/hal/hal_facade.proto20
-rw-r--r--system/blueberry/facade/hci/acl_manager_facade.proto53
-rw-r--r--system/blueberry/facade/hci/controller_facade.proto96
-rw-r--r--system/blueberry/facade/hci/hci_facade.proto23
-rw-r--r--system/blueberry/facade/hci/le_acl_manager_facade.proto56
-rw-r--r--system/blueberry/facade/hci/le_advertising_manager_facade.proto180
-rw-r--r--system/blueberry/facade/hci/le_initiator_address_facade.proto28
-rw-r--r--system/blueberry/facade/hci/le_scanning_manager_facade.proto69
-rw-r--r--system/blueberry/facade/l2cap/classic/facade.proto130
-rw-r--r--system/blueberry/facade/l2cap/le/facade.proto85
-rw-r--r--system/blueberry/facade/neighbor/facade.proto13
-rw-r--r--system/blueberry/facade/rootservice.proto34
-rw-r--r--system/blueberry/facade/topshim/facade.proto266
-rw-r--r--system/blueberry/tests/gd/cert/adb.py175
-rw-r--r--system/blueberry/tests/gd/cert/asserts.py57
-rw-r--r--system/blueberry/tests/gd/cert/async_subprocess_logger.py90
-rw-r--r--system/blueberry/tests/gd/cert/behavior.py173
-rw-r--r--system/blueberry/tests/gd/cert/capture.py41
-rw-r--r--system/blueberry/tests/gd/cert/captures.py94
-rw-r--r--system/blueberry/tests/gd/cert/cert_self_test.py659
-rw-r--r--system/blueberry/tests/gd/cert/closable.py48
-rw-r--r--system/blueberry/tests/gd/cert/context.py224
-rw-r--r--system/blueberry/tests/gd/cert/event_stream.py304
-rw-r--r--system/blueberry/tests/gd/cert/gd_base_test.py305
-rw-r--r--system/blueberry/tests/gd/cert/gd_device.py866
-rw-r--r--system/blueberry/tests/gd/cert/logging_client_interceptor.py86
-rw-r--r--system/blueberry/tests/gd/cert/matchers.py295
-rw-r--r--system/blueberry/tests/gd/cert/metadata.py79
-rw-r--r--system/blueberry/tests/gd/cert/os_utils.py154
-rw-r--r--system/blueberry/tests/gd/cert/performance_test_logger.py71
-rw-r--r--system/blueberry/tests/gd/cert/pts_base_test.py29
-rw-r--r--system/blueberry/tests/gd/cert/py_acl_manager.py98
-rw-r--r--system/blueberry/tests/gd/cert/py_hal.py341
-rw-r--r--system/blueberry/tests/gd/cert/py_hci.py294
-rw-r--r--system/blueberry/tests/gd/cert/py_le_acl_manager.py163
-rw-r--r--system/blueberry/tests/gd/cert/test_decorators.py267
-rw-r--r--system/blueberry/tests/gd/cert/tracelogger.py63
-rw-r--r--system/blueberry/tests/gd/cert/truth.py158
-rw-r--r--system/blueberry/tests/gd/devices_config.yaml44
-rw-r--r--system/blueberry/tests/gd/gd_all_tests.py43
-rw-r--r--system/blueberry/tests/gd/gd_postsubmit_tests.py26
-rw-r--r--system/blueberry/tests/gd/gd_presubmit_tests.py29
-rw-r--r--system/blueberry/tests/gd/gd_test_runner.py68
-rw-r--r--system/blueberry/tests/gd/hal/simple_hal_test.py139
-rw-r--r--system/blueberry/tests/gd/hci/acl_manager_test.py124
-rw-r--r--system/blueberry/tests/gd/hci/controller_test.py59
-rw-r--r--system/blueberry/tests/gd/hci/direct_hci_test.py324
-rw-r--r--system/blueberry/tests/gd/hci/le_acl_manager_test.py438
-rw-r--r--system/blueberry/tests/gd/hci/le_advertising_manager_test.py328
-rw-r--r--system/blueberry/tests/gd/hci/le_extended_config.json6
-rw-r--r--system/blueberry/tests/gd/hci/le_extended_scanning_manager_test.py39
-rw-r--r--system/blueberry/tests/gd/hci/le_legacy_config.json6
-rw-r--r--system/blueberry/tests/gd/hci/le_scanning_manager_test.py250
-rw-r--r--system/blueberry/tests/gd/hci/le_scanning_with_security_test.py97
-rw-r--r--system/blueberry/tests/gd/host_config.yaml32
-rw-r--r--system/blueberry/tests/gd/iso/cert_le_iso.py56
-rw-r--r--system/blueberry/tests/gd/iso/le_iso_test.py252
-rw-r--r--system/blueberry/tests/gd/rust_devices_config.yaml44
-rw-r--r--system/blueberry/tests/gd/rust_host_config.yaml32
-rw-r--r--system/blueberry/tests/topshim/adapter/adapter_test.py74
-rw-r--r--system/blueberry/tests/topshim/hfp/hfp_test.py72
-rw-r--r--system/blueberry/tests/topshim/lib/adapter_client.py168
-rw-r--r--system/blueberry/tests/topshim/lib/async_closable.py50
-rw-r--r--system/blueberry/tests/topshim/lib/gatt_client.py385
-rw-r--r--system/blueberry/tests/topshim/lib/hf_client_client.py60
-rw-r--r--system/blueberry/tests/topshim/lib/hfp_client.py110
-rw-r--r--system/blueberry/tests/topshim/lib/oob_data.py50
-rw-r--r--system/blueberry/tests/topshim/lib/security_client.py71
-rw-r--r--system/blueberry/tests/topshim/lib/topshim_base_test.py238
-rw-r--r--system/blueberry/tests/topshim/lib/topshim_device.py260
-rw-r--r--system/blueberry/tests/topshim/power/suspend_test.py102
-rw-r--r--system/blueberry/tests/topshim/security/classic_security_test.py38
-rw-r--r--system/blueberry/tests/topshim/security/le_security_test.py41
-rw-r--r--system/blueberry/tests/topshim/topshim_host_config.yaml32
-rw-r--r--system/blueberry/tests/topshim/topshim_test_runner.py69
-rw-r--r--system/bta/Android.bp33
-rw-r--r--system/bta/BUILD.gn3
-rw-r--r--system/bta/ag/bta_ag_act.cc1
-rw-r--r--system/bta/ag/bta_ag_int.h31
-rw-r--r--system/bta/ag/bta_ag_rfc.cc13
-rw-r--r--system/bta/av/bta_av_aact.cc160
-rw-r--r--system/bta/av/bta_av_act.cc6
-rw-r--r--system/bta/av/bta_av_int.h1
-rw-r--r--system/bta/av/bta_av_main.cc14
-rw-r--r--system/bta/bundler.gni (renamed from system/gd/dumpsys/bundler/bundler.gni)0
-rw-r--r--system/bta/csis/csis_client.cc7
-rw-r--r--system/bta/dm/bta_dm_act.cc11
-rw-r--r--system/bta/dm/bta_dm_device_search.cc18
-rw-r--r--system/bta/dm/bta_dm_device_search_int.h1
-rw-r--r--system/bta/dm/bta_dm_disc.cc9
-rw-r--r--system/bta/dm/bta_dm_disc_int.h1
-rw-r--r--system/bta/dm/bta_dm_disc_sdp.cc9
-rw-r--r--system/bta/dm/bta_dm_gatt_client.cc42
-rw-r--r--system/bta/dm/bta_dm_int.h9
-rw-r--r--system/bta/dm/bta_dm_main.cc1
-rw-r--r--system/bta/dm/bta_dm_sec_api.cc7
-rw-r--r--system/bta/gatt/bta_gattc_act.cc7
-rw-r--r--system/bta/gatt/bta_gattc_cache.cc2
-rw-r--r--system/bta/gatt/bta_gattc_int.h6
-rw-r--r--system/bta/gatt/bta_gattc_main.cc2
-rw-r--r--system/bta/gatt/bta_gattc_queue.cc73
-rw-r--r--system/bta/gatt/bta_gattc_utils.cc10
-rw-r--r--system/bta/gatt/bta_gatts_act.cc12
-rw-r--r--system/bta/groups/groups.cc2
-rw-r--r--system/bta/has/has_client_test.cc7
-rw-r--r--system/bta/has/has_ctp.cc2
-rw-r--r--system/bta/hearing_aid/hearing_aid.cc9
-rw-r--r--system/bta/hf_client/bta_hf_client_rfc.cc10
-rw-r--r--system/bta/hf_client/bta_hf_client_sdp.cc14
-rw-r--r--system/bta/hh/bta_hh_act.cc17
-rw-r--r--system/bta/hh/bta_hh_le.cc14
-rw-r--r--system/bta/include/bta_api.h14
-rw-r--r--system/bta/include/bta_api_data_types.h3
-rw-r--r--system/bta/include/bta_gatt_api.h5
-rw-r--r--system/bta/include/bta_gatt_queue.h11
-rw-r--r--system/bta/include/bta_hh_api.h3
-rw-r--r--system/bta/include/bta_jv_api.h39
-rw-r--r--system/bta/include/bta_ras_api.h2
-rw-r--r--system/bta/include/bta_sdp_api.h4
-rw-r--r--system/bta/include/bta_sec_api.h1
-rw-r--r--system/bta/jv/bta_jv_act.cc102
-rw-r--r--system/bta/jv/bta_jv_api.cc9
-rw-r--r--system/bta/jv/bta_jv_int.h6
-rw-r--r--system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc25
-rw-r--r--system/bta/le_audio/client.cc311
-rw-r--r--system/bta/le_audio/device_groups.cc6
-rw-r--r--system/bta/le_audio/device_groups.h4
-rw-r--r--system/bta/le_audio/devices.cc15
-rw-r--r--system/bta/le_audio/le_audio_client_test.cc295
-rw-r--r--system/bta/le_audio/le_audio_health_status.cc3
-rw-r--r--system/bta/le_audio/le_audio_log_history.cc2
-rw-r--r--system/bta/le_audio/state_machine.cc26
-rw-r--r--system/bta/le_audio/state_machine_test.cc62
-rw-r--r--system/bta/ras/ras_client.cc41
-rw-r--r--system/bta/ras/ras_server.cc19
-rw-r--r--system/bta/ras/ras_types.h1
-rw-r--r--system/bta/sys/bta_sys.h3
-rw-r--r--system/bta/test/common/bta_gatt_queue_mock.cc3
-rw-r--r--system/bta/vc/device.cc84
-rw-r--r--system/bta/vc/devices.h12
-rw-r--r--system/bta/vc/devices_test.cc50
-rw-r--r--system/bta/vc/vc.cc22
-rw-r--r--system/btcore/src/hal_util.cc3
-rw-r--r--system/btif/Android.bp24
-rw-r--r--system/btif/BUILD.gn1
-rw-r--r--system/btif/co/bta_av_co.cc9
-rw-r--r--system/btif/include/btif_hh.h5
-rw-r--r--system/btif/include/btif_sock_hal.h (renamed from system/gd/dumpsys/dumpsys_test_data.h)9
-rw-r--r--system/btif/include/btif_sock_l2cap.h12
-rw-r--r--system/btif/include/btif_sock_rfc.h13
-rw-r--r--system/btif/src/bluetooth.cc4
-rw-r--r--system/btif/src/btif_a2dp.cc9
-rw-r--r--system/btif/src/btif_a2dp_sink.cc1
-rw-r--r--system/btif/src/btif_a2dp_source.cc12
-rw-r--r--system/btif/src/btif_av.cc13
-rw-r--r--system/btif/src/btif_core.cc11
-rw-r--r--system/btif/src/btif_debug_conn.cc2
-rw-r--r--system/btif/src/btif_dm.cc120
-rw-r--r--system/btif/src/btif_gatt_server.cc49
-rw-r--r--system/btif/src/btif_hf.cc3
-rw-r--r--system/btif/src/btif_hh.cc40
-rw-r--r--system/btif/src/btif_rc.cc2
-rw-r--r--system/btif/src/btif_sock.cc54
-rw-r--r--system/btif/src/btif_sock_hal.cc70
-rw-r--r--system/btif/src/btif_sock_l2cap.cc504
-rw-r--r--system/btif/src/btif_sock_logging.cc3
-rw-r--r--system/btif/src/btif_sock_rfc.cc426
-rw-r--r--system/btif/src/btif_storage.cc8
-rw-r--r--system/btif/src/stack_manager.cc13
-rw-r--r--system/btif/test/btif_core_test.cc30
-rw-r--r--system/common/Android.bp1
-rw-r--r--system/common/BUILD.gn1
-rw-r--r--system/common/le_conn_params.cc142
-rw-r--r--system/common/le_conn_params.h51
-rw-r--r--system/common/message_loop_thread.cc3
-rw-r--r--system/device/Android.bp3
-rw-r--r--system/device/fuzzer/Android.bp3
-rw-r--r--system/gd/Android.bp162
-rw-r--r--system/gd/BUILD.gn24
-rw-r--r--system/gd/cert/change_waiter.py18
-rwxr-xr-xsystem/gd/cert/gen_html_coverage.sh10
-rwxr-xr-xsystem/gd/cert/irun10
-rwxr-xr-xsystem/gd/cert/run495
-rwxr-xr-xsystem/gd/cert/set_up_and_run_device_cert.sh158
-rw-r--r--system/gd/common/audit_log.cc7
-rw-r--r--system/gd/common/interfaces/ILoggable.h45
-rw-r--r--system/gd/dumpsys/Android.bp212
-rw-r--r--system/gd/dumpsys/BUILD.gn43
-rw-r--r--system/gd/dumpsys/bluetooth_flatbuffer_test.cc71
-rw-r--r--system/gd/dumpsys/bluetooth_flatbuffer_test.fbs17
-rw-r--r--system/gd/dumpsys/bundler/Android.bp91
-rw-r--r--system/gd/dumpsys/bundler/BUILD.gn50
-rw-r--r--system/gd/dumpsys/bundler/bundler.cc322
-rw-r--r--system/gd/dumpsys/bundler/bundler.h71
-rw-r--r--system/gd/dumpsys/bundler/bundler_schema.fbs19
-rwxr-xr-xsystem/gd/dumpsys/bundler/extract_files_and_call.py58
-rw-r--r--system/gd/dumpsys/bundler/main.cc27
-rw-r--r--system/gd/dumpsys/bundler/test.bfbsbin456 -> 0 bytes
-rw-r--r--system/gd/dumpsys/bundler/test.cc89
-rw-r--r--system/gd/dumpsys/dumpsys.h24
-rw-r--r--system/gd/dumpsys/filter.cc95
-rw-r--r--system/gd/dumpsys/filter.h27
-rw-r--r--system/gd/dumpsys/filter_test.cc122
-rw-r--r--system/gd/dumpsys/internal/filter_internal.cc289
-rw-r--r--system/gd/dumpsys/internal/filter_internal.h157
-rw-r--r--system/gd/dumpsys/internal/filter_internal_test.cc424
-rw-r--r--system/gd/dumpsys/internal/test_data/float.bfbsbin240 -> 0 bytes
-rw-r--r--system/gd/dumpsys/internal/test_data/float.fbs7
-rw-r--r--system/gd/dumpsys/internal/test_data/float_bfbs.h18
-rw-r--r--system/gd/dumpsys/internal/test_data/integer.bfbsbin244 -> 0 bytes
-rw-r--r--system/gd/dumpsys/internal/test_data/integer.fbs7
-rw-r--r--system/gd/dumpsys/internal/test_data/integer_bfbs.h19
-rw-r--r--system/gd/dumpsys/internal/test_data/mkfiles9
-rw-r--r--system/gd/dumpsys/internal/test_data/root.h17
-rw-r--r--system/gd/dumpsys/internal/test_data/string.bfbsbin208 -> 0 bytes
-rw-r--r--system/gd/dumpsys/internal/test_data/string.fbs7
-rw-r--r--system/gd/dumpsys/internal/test_data/string_bfbs.h16
-rw-r--r--system/gd/dumpsys/internal/test_data/struct.bfbsbin392 -> 0 bytes
-rw-r--r--system/gd/dumpsys/internal/test_data/struct.fbs11
-rw-r--r--system/gd/dumpsys/internal/test_data/struct_bfbs.h29
-rw-r--r--system/gd/dumpsys/reflection_schema.cc91
-rw-r--r--system/gd/dumpsys/reflection_schema.h47
-rw-r--r--system/gd/dumpsys/reflection_schema_test.cc63
-rw-r--r--system/gd/dumpsys/test_data/bar.fbs12
-rw-r--r--system/gd/dumpsys/test_data/bar.h17
-rw-r--r--system/gd/dumpsys/test_data/baz.fbs35
-rw-r--r--system/gd/dumpsys/test_data/baz.h34
-rw-r--r--system/gd/dumpsys/test_data/foo.fbs25
-rw-r--r--system/gd/dumpsys/test_data/foo.h42
-rw-r--r--system/gd/dumpsys/test_data/qux.fbs13
-rw-r--r--system/gd/dumpsys/test_data/qux.h28
-rw-r--r--system/gd/dumpsys/test_data/root.fbs27
-rw-r--r--system/gd/dumpsys/test_data/root.h17
-rw-r--r--system/gd/dumpsys_data.fbs25
-rw-r--r--system/gd/facade/facade_main.cc174
-rw-r--r--system/gd/facade/grpc_root_server.cc157
-rw-r--r--system/gd/facade/read_only_property_server.cc57
-rw-r--r--system/gd/facade/read_only_property_server.h45
-rw-r--r--system/gd/grpc/grpc_event_queue.h86
-rw-r--r--system/gd/grpc/grpc_module.cc112
-rw-r--r--system/gd/grpc/grpc_module.h81
-rw-r--r--system/gd/hal/Android.bp21
-rw-r--r--system/gd/hal/BUILD.gn9
-rw-r--r--system/gd/hal/facade.cc155
-rw-r--r--system/gd/hal/facade.h48
-rw-r--r--system/gd/hal/ranging_hal.h1
-rw-r--r--system/gd/hal/ranging_hal_android.cc19
-rw-r--r--system/gd/hal/ranging_hal_host.cc2
-rw-r--r--system/gd/hal/snoop_logger.cc1
-rw-r--r--system/gd/hal/snoop_logger_test.cc3
-rw-r--r--system/gd/hal/socket_hal.h212
-rw-r--r--system/gd/hal/socket_hal_android.cc275
-rw-r--r--system/gd/hal/socket_hal_host.cc44
-rw-r--r--system/gd/hci/Android.bp13
-rw-r--r--system/gd/hci/acl_manager.cc3
-rw-r--r--system/gd/hci/acl_manager/acl_scheduler.cc2
-rw-r--r--system/gd/hci/acl_manager/classic_acl_connection.cc9
-rw-r--r--system/gd/hci/acl_manager/classic_acl_connection.h1
-rw-r--r--system/gd/hci/acl_manager/classic_acl_connection_test.cc12
-rw-r--r--system/gd/hci/acl_manager/classic_impl.h6
-rw-r--r--system/gd/hci/acl_manager/le_acl_connection.cc9
-rw-r--r--system/gd/hci/acl_manager/le_acl_connection.h1
-rw-r--r--system/gd/hci/acl_manager/le_impl.h89
-rw-r--r--system/gd/hci/acl_manager/le_impl_test.cc138
-rw-r--r--system/gd/hci/address.h15
-rw-r--r--system/gd/hci/address_with_type.h16
-rw-r--r--system/gd/hci/address_with_type_test.cc9
-rw-r--r--system/gd/hci/class_of_device.h2
-rw-r--r--system/gd/hci/controller.cc13
-rw-r--r--system/gd/hci/controller.h2
-rw-r--r--system/gd/hci/controller_interface.h2
-rw-r--r--system/gd/hci/controller_interface_mock.h1
-rw-r--r--system/gd/hci/controller_mock.h1
-rw-r--r--system/gd/hci/controller_test.cc1
-rw-r--r--system/gd/hci/distance_measurement_manager.cc210
-rw-r--r--system/gd/hci/distance_measurement_manager.h1
-rw-r--r--system/gd/hci/facade/acl_manager_facade.cc580
-rw-r--r--system/gd/hci/facade/acl_manager_facade.h45
-rw-r--r--system/gd/hci/facade/controller_facade.cc185
-rw-r--r--system/gd/hci/facade/controller_facade.h45
-rw-r--r--system/gd/hci/facade/facade.cc251
-rw-r--r--system/gd/hci/facade/facade.h45
-rw-r--r--system/gd/hci/facade/le_acl_manager_facade.cc472
-rw-r--r--system/gd/hci/facade/le_acl_manager_facade.h45
-rw-r--r--system/gd/hci/facade/le_advertising_manager_facade.cc517
-rw-r--r--system/gd/hci/facade/le_advertising_manager_facade.h44
-rw-r--r--system/gd/hci/facade/le_initiator_address_facade.cc131
-rw-r--r--system/gd/hci/facade/le_initiator_address_facade.h45
-rw-r--r--system/gd/hci/facade/le_scanning_manager_facade.cc202
-rw-r--r--system/gd/hci/facade/le_scanning_manager_facade.h44
-rw-r--r--system/gd/hci/le_address_manager.cc19
-rw-r--r--system/gd/hci/le_address_manager_test.cc2
-rw-r--r--system/gd/hci/le_advertising_manager.cc15
-rw-r--r--system/gd/hci/le_scanning_manager.cc11
-rw-r--r--system/gd/hci/le_scanning_manager_test.cc5
-rw-r--r--system/gd/lpp/Android.bp (renamed from system/gd/shim/Android.bp)11
-rw-r--r--system/gd/lpp/BUILD.gn (renamed from system/gd/shim/BUILD.gn)17
-rw-r--r--system/gd/lpp/lpp_offload_interface.h75
-rw-r--r--system/gd/lpp/lpp_offload_interface_mock.h (renamed from system/gd/facade/grpc_root_server.h)33
-rw-r--r--system/gd/lpp/lpp_offload_manager.cc100
-rw-r--r--system/gd/lpp/lpp_offload_manager.h62
-rw-r--r--system/gd/metrics/bluetooth_event.h3
-rw-r--r--system/gd/metrics/chromeos/metrics_event.cc9
-rw-r--r--system/gd/module.cc7
-rw-r--r--system/gd/module.h16
-rw-r--r--system/gd/module_dumper.cc62
-rw-r--r--system/gd/module_dumper.h39
-rw-r--r--system/gd/module_dumper_flatbuffer.h28
-rw-r--r--system/gd/module_unittest.cc78
-rw-r--r--system/gd/module_unittest.fbs10
-rw-r--r--system/gd/module_unittest_generated.h86
-rw-r--r--system/gd/neighbor/Android.bp7
-rw-r--r--system/gd/neighbor/facade/facade.cc75
-rw-r--r--system/gd/neighbor/facade/facade.h45
-rw-r--r--system/gd/os/android/metrics.cc2
-rw-r--r--system/gd/os/linux_generic/reactor.cc10
-rw-r--r--system/gd/os/linux_generic/wakelock_manager.cc55
-rw-r--r--system/gd/os/linux_generic/wakelock_manager_unittest.cc26
-rw-r--r--system/gd/os/logging/log_adapter.h3
-rw-r--r--system/gd/os/rand.h7
-rw-r--r--system/gd/os/wakelock_manager.fbs26
-rw-r--r--system/gd/os/wakelock_manager.h11
-rw-r--r--system/gd/rust/linux/client/src/callbacks.rs4
-rw-r--r--system/gd/rust/linux/client/src/command_handler.rs11
-rw-r--r--system/gd/rust/linux/client/src/dbus_iface.rs8
-rw-r--r--system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs5
-rw-r--r--system/gd/rust/linux/mgmt/src/bluetooth_manager.rs5
-rw-r--r--system/gd/rust/linux/mgmt/src/config_util.rs34
-rw-r--r--system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs3
-rw-r--r--system/gd/rust/linux/service/src/iface_bluetooth_qa.rs8
-rw-r--r--system/gd/rust/linux/stack/src/battery_provider_manager.rs16
-rw-r--r--system/gd/rust/linux/stack/src/bluetooth.rs5
-rw-r--r--system/gd/rust/linux/stack/src/bluetooth_qa.rs17
-rw-r--r--system/gd/rust/linux/stack/src/lib.rs5
-rw-r--r--system/gd/rust/topshim/Android.bp1
-rw-r--r--system/gd/rust/topshim/facade/.gitignore1
-rw-r--r--system/gd/rust/topshim/facade/Android.bp104
-rw-r--r--system/gd/rust/topshim/facade/src/adapter_service.rs385
-rw-r--r--system/gd/rust/topshim/facade/src/gatt_service.rs745
-rw-r--r--system/gd/rust/topshim/facade/src/hf_client_service.rs143
-rw-r--r--system/gd/rust/topshim/facade/src/hfp_service.rs212
-rw-r--r--system/gd/rust/topshim/facade/src/main.rs168
-rw-r--r--system/gd/rust/topshim/facade/src/media_service.rs100
-rw-r--r--system/gd/rust/topshim/facade/src/security_service.rs78
-rw-r--r--system/gd/rust/topshim/facade/src/utils.rs34
-rw-r--r--system/gd/rust/topshim/macros/src/lib.rs16
-rw-r--r--system/gd/rust/topshim/src/profiles/gatt.rs15
-rw-r--r--system/gd/rust/topshim/src/profiles/socket.rs27
-rw-r--r--system/gd/shim/dumpsys.cc189
-rw-r--r--system/gd/shim/dumpsys.h55
-rw-r--r--system/gd/shim/dumpsys_test.cc132
-rw-r--r--system/gd/shim/test_data/dumpsys_data.bfbsbin736 -> 0 bytes
-rw-r--r--system/gd/shim/test_data/dumpsys_test_data_binbin884 -> 0 bytes
-rw-r--r--system/gd/shim/test_data/dumpsys_test_data_bin.h76
-rw-r--r--system/gd/stack_manager.cc105
-rw-r--r--system/gd/stack_manager.h50
-rw-r--r--system/gd/stack_manager_unittest.cc58
-rw-r--r--system/gd/storage/storage_module.cc4
-rw-r--r--system/gd/storage/storage_module_test.cc1
-rw-r--r--system/include/Android.bp2
-rw-r--r--system/include/hardware/ble_scanner.h24
-rw-r--r--system/include/hardware/bluetooth.h14
-rw-r--r--system/include/hardware/bt_gatt.h3
-rw-r--r--system/include/hardware/bt_hh.h3
-rw-r--r--system/include/hardware/bt_sock.h30
-rw-r--r--system/main/Android.bp14
-rw-r--r--system/main/shim/BUILD.gn6
-rw-r--r--system/main/shim/acl.cc168
-rw-r--r--system/main/shim/acl.h2
-rw-r--r--system/main/shim/acl_api.cc1
-rw-r--r--system/main/shim/distance_measurement_manager.cc15
-rw-r--r--system/main/shim/dumpsys.cc15
-rw-r--r--system/main/shim/dumpsys.h2
-rw-r--r--system/main/shim/entry.cc34
-rw-r--r--system/main/shim/entry.h7
-rw-r--r--system/main/shim/le_advertising_manager.cc4
-rw-r--r--system/main/shim/le_scanning_manager.cc8
-rw-r--r--system/main/shim/metrics_api.cc28
-rw-r--r--system/main/shim/metrics_api.h25
-rw-r--r--system/main/shim/stack.cc152
-rw-r--r--system/main/shim/stack.h37
-rw-r--r--system/main/test/main_shim_dumpsys_test.cc74
-rw-r--r--system/main/test/main_shim_test.cc6
-rw-r--r--system/osi/src/stack_power_telemetry.cc13
-rw-r--r--system/pdl/hci/hci_packets.pdl16
-rw-r--r--system/pdl/hci/include/hci/address.h18
-rw-r--r--system/profile/avrcp/connection_handler.cc16
-rw-r--r--system/profile/avrcp/device.cc15
-rw-r--r--system/profile/avrcp/tests/avrcp_connection_handler_test.cc24
-rw-r--r--system/rust/Android.bp14
-rw-r--r--system/setup.py101
-rw-r--r--system/stack/Android.bp86
-rw-r--r--system/stack/a2dp/a2dp_sbc.cc12
-rw-r--r--system/stack/acl/btm_pm.cc12
-rw-r--r--system/stack/ais/ais_ble.cc5
-rw-r--r--system/stack/avct/avct_api.cc3
-rw-r--r--system/stack/avct/avct_bcb_act.cc9
-rw-r--r--system/stack/avct/avct_lcb_act.cc9
-rw-r--r--system/stack/avdt/avdt_ad.cc9
-rw-r--r--system/stack/avdt/avdt_api.cc8
-rw-r--r--system/stack/avdt/avdt_scb_act.cc7
-rw-r--r--system/stack/bnep/bnep_utils.cc15
-rw-r--r--system/stack/btm/btm_ble_gap.cc41
-rw-r--r--system/stack/btm/btm_ble_sec.cc115
-rw-r--r--system/stack/btm/btm_dev.cc7
-rw-r--r--system/stack/btm/btm_inq.cc43
-rw-r--r--system/stack/btm/btm_iso_impl.h47
-rw-r--r--system/stack/btm/btm_main.cc4
-rw-r--r--system/stack/btm/btm_sco.cc39
-rw-r--r--system/stack/btm/btm_sec.cc47
-rw-r--r--system/stack/btm/security_device_record.h31
-rw-r--r--system/stack/connection_manager/connection_manager.cc127
-rw-r--r--system/stack/connection_manager/connection_manager.h32
-rw-r--r--system/stack/eatt/eatt.h7
-rw-r--r--system/stack/fuzzers/l2cap_fuzzer.cc7
-rw-r--r--system/stack/fuzzers/rfcomm_fuzzer.cc63
-rw-r--r--system/stack/gap/gap_conn.cc103
-rw-r--r--system/stack/gatt/gatt_api.cc9
-rw-r--r--system/stack/gatt/gatt_int.h13
-rw-r--r--system/stack/gatt/gatt_main.cc2
-rw-r--r--system/stack/gatt/gatt_sr.cc43
-rw-r--r--system/stack/gatt/gatt_utils.cc3
-rw-r--r--system/stack/hid/hid_conn.h3
-rw-r--r--system/stack/hid/hidh_api.cc5
-rw-r--r--system/stack/hid/hidh_conn.cc28
-rw-r--r--system/stack/include/avdt_api.h3
-rw-r--r--system/stack/include/btm_api_types.h2
-rw-r--r--system/stack/include/btm_sec_api_types.h13
-rw-r--r--system/stack/include/btm_status.h4
-rw-r--r--system/stack/include/gap_api.h37
-rw-r--r--system/stack/include/gatt_api.h5
-rw-r--r--system/stack/include/hci_error_code.h3
-rw-r--r--system/stack/include/hiddefs.h3
-rw-r--r--system/stack/include/l2cap_interface.h35
-rw-r--r--system/stack/include/l2cap_types.h2
-rw-r--r--system/stack/include/l2cdefs.h1
-rw-r--r--system/stack/include/pan_api.h9
-rw-r--r--system/stack/include/port_api.h46
-rw-r--r--system/stack/include/rfcdefs.h5
-rw-r--r--system/stack/include/sdp_api.h1
-rw-r--r--system/stack/include/sdp_status.h3
-rw-r--r--system/stack/include/sdpdefs.h9
-rw-r--r--system/stack/include/smp_api.h9
-rw-r--r--system/stack/include/smp_api_types.h1
-rw-r--r--system/stack/include/smp_status.h3
-rw-r--r--system/stack/include/stack_metrics_logging.h9
-rw-r--r--system/stack/l2cap/internal/l2c_api.h35
-rw-r--r--system/stack/l2cap/l2c_api.cc60
-rw-r--r--system/stack/l2cap/l2c_api.h5
-rw-r--r--system/stack/l2cap/l2c_ble.cc59
-rw-r--r--system/stack/l2cap/l2c_ble_conn_params.cc76
-rw-r--r--system/stack/l2cap/l2c_int.h8
-rw-r--r--system/stack/l2cap/l2c_utils.cc3
-rw-r--r--system/stack/l2cap/l2cap_api.cc15
-rw-r--r--system/stack/metrics/stack_metrics_logging.cc13
-rw-r--r--system/stack/mmc/main.cc4
-rw-r--r--system/stack/pan/pan_api.cc6
-rw-r--r--system/stack/pan/pan_main.cc1
-rw-r--r--system/stack/rfcomm/port_api.cc88
-rw-r--r--system/stack/rfcomm/port_int.h2
-rw-r--r--system/stack/rfcomm/port_rfc.cc9
-rw-r--r--system/stack/rfcomm/rfc_mx_fsm.cc2
-rw-r--r--system/stack/rfcomm/rfc_port_if.cc10
-rw-r--r--system/stack/rfcomm/rfc_ts_frames.cc5
-rw-r--r--system/stack/rnr/remote_name_request.cc12
-rw-r--r--system/stack/rnr/remote_name_request.h2
-rw-r--r--system/stack/sdp/sdp_api.cc1
-rw-r--r--system/stack/sdp/sdp_discovery.cc11
-rw-r--r--system/stack/sdp/sdpint.h3
-rw-r--r--system/stack/smp/smp_act.cc8
-rw-r--r--system/stack/smp/smp_api.cc5
-rw-r--r--system/stack/smp/smp_int.h2
-rw-r--r--system/stack/smp/smp_main.cc6
-rw-r--r--system/stack/smp/smp_utils.cc2
-rw-r--r--system/stack/srvc/srvc_dis.cc5
-rw-r--r--system/stack/test/a2dp/mock_bta_av_codec.cc4
-rw-r--r--system/stack/test/btm/stack_btm_dm_inq_db_test.cc3
-rw-r--r--system/stack/test/btm/stack_btm_inq_test.cc8
-rw-r--r--system/stack/test/btm/stack_btm_sec_test.cc4
-rw-r--r--system/stack/test/btm/stack_btm_test.cc8
-rw-r--r--system/stack/test/btm_iso_test.cc14
-rw-r--r--system/stack/test/common/mock_btif_storage.cc33
-rw-r--r--system/stack/test/common/mock_btif_storage.h45
-rw-r--r--system/stack/test/common/mock_btm_api_layer.cc4
-rw-r--r--system/stack/test/common/mock_btm_layer.cc4
-rw-r--r--system/stack/test/common/mock_btu_layer.cc24
-rw-r--r--system/stack/test/common/mock_l2cap_layer.cc17
-rw-r--r--system/stack/test/common/mock_l2cap_layer.h1
-rw-r--r--system/stack/test/common/mock_stack_avdt_msg.cc5
-rw-r--r--system/stack/test/connection_manager_test.cc26
-rw-r--r--system/stack/test/eatt/eatt_test.cc10
-rw-r--r--system/stack/test/fuzzers/Android.bp1
-rw-r--r--system/stack/test/gatt/mock_gatt_utils_ref.cc51
-rw-r--r--system/stack/test/gatt/stack_gatt_test.cc2
-rw-r--r--system/stack/test/hci/stack_hci_test.cc2
-rw-r--r--system/stack/test/hid/stack_hid_test.cc5
-rw-r--r--system/stack/test/rfcomm/stack_rfcomm_test.cc29
-rw-r--r--system/stack/test/rfcomm/stack_rfcomm_test_utils.cc5
-rw-r--r--system/stack/test/sdp/stack_sdp_test.cc13
-rw-r--r--system/stack/test/sdp/stack_sdp_utils_test.cc17
-rw-r--r--system/stack/test/stack_avdtp_test.cc3
-rw-r--r--system/stack/test/stack_rnr_test.cc7
-rw-r--r--system/stack/test/stack_smp_test.cc81
-rw-r--r--system/test/Android.bp5
-rw-r--r--system/test/headless/Android.bp1
-rw-r--r--system/test/headless/bt_stack_info.cc3
-rw-r--r--system/test/mock/mock_bta_jv_api.cc4
-rw-r--r--system/test/mock/mock_btif_sock_l2cap.cc66
-rw-r--r--system/test/mock/mock_btif_sock_l2cap.h63
-rw-r--r--system/test/mock/mock_btif_sock_rfc.cc10
-rw-r--r--system/test/mock/mock_btif_sock_rfc.h19
-rw-r--r--system/test/mock/mock_main_shim_acl.cc2
-rw-r--r--system/test/mock/mock_main_shim_dumpsys.cc3
-rw-r--r--system/test/mock/mock_main_shim_entry.cc10
-rw-r--r--system/test/mock/mock_main_shim_entry.h2
-rw-r--r--system/test/mock/mock_main_shim_metrics_api.cc17
-rw-r--r--system/test/mock/mock_main_shim_metrics_api.h38
-rw-r--r--system/test/mock/mock_main_shim_stack.cc8
-rw-r--r--system/test/mock/mock_stack_connection_manager.cc9
-rw-r--r--system/test/mock/mock_stack_gap_conn.cc12
-rw-r--r--system/test/mock/mock_stack_hidh.cc7
-rw-r--r--system/test/mock/mock_stack_l2cap_api.cc10
-rw-r--r--system/test/mock/mock_stack_l2cap_api.h20
-rw-r--r--system/test/mock/mock_stack_l2cap_ble.cc5
-rw-r--r--system/test/mock/mock_stack_l2cap_ble.h9
-rw-r--r--system/test/mock/mock_stack_l2cap_interface.h3
-rw-r--r--system/test/mock/mock_stack_metrics_logging.cc19
-rw-r--r--system/test/mock/mock_stack_metrics_logging.h35
-rw-r--r--system/test/mock/mock_stack_rfcomm_port_api.cc11
-rw-r--r--system/test/mock/mock_stack_smp_api.cc5
-rw-r--r--system/test/mock/mock_stack_srvc_dis.cc8
-rw-r--r--system/test/suite/Android.bp4
-rw-r--r--system/test/suite/gatt/gatt_test.cc13
-rw-r--r--system/test/suite/gatt/gatt_test.h1
-rw-r--r--system/types/Android.bp2
-rw-r--r--system/types/remote_version_type.h5
762 files changed, 17581 insertions, 28730 deletions
diff --git a/Android.bp b/Android.bp
index 9142bd51ae..7ec7305d0a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -115,6 +115,7 @@ java_defaults {
"-Xep:ClassCanBeStatic:ERROR",
"-Xep:DateFormatConstant:ERROR",
"-Xep:DirectInvocationOnMock:ERROR",
+ "-Xep:DuplicateBranches:ERROR",
"-Xep:EmptyBlockTag:ERROR",
"-Xep:EmptyCatch:ERROR",
"-Xep:EnumOrdinal:ERROR",
@@ -152,6 +153,7 @@ java_defaults {
"-Xep:NullableVoid:ERROR",
"-Xep:ObjectEqualsForPrimitives:ERROR",
"-Xep:OperatorPrecedence:ERROR",
+ "-Xep:RedundantControlFlow:ERROR",
"-Xep:ReferenceEquality:ERROR",
"-Xep:ReturnAtTheEndOfVoidFunction:ERROR",
"-Xep:ReturnFromVoid:ERROR",
diff --git a/OWNERS_leaudio b/OWNERS_leaudio
index 0ba606bbf0..30db38d799 100644
--- a/OWNERS_leaudio
+++ b/OWNERS_leaudio
@@ -1,4 +1,3 @@
siyuanh@google.com
jpawlowski@google.com
rongxuan@google.com
-yuyangh@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
index bd98b7d91c..5fc31de514 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,4 +1,183 @@
{
+ "bt-mainline-presubmit": [
+ {
+ "name": "CtsBluetoothTestCases"
+ },
+ {
+ "name": "GoogleBluetoothInstrumentationTests"
+ },
+ {
+ "name": "FrameworkBluetoothTests"
+ },
+ {
+ "name": "ServiceBluetoothTests"
+ },
+ {
+ "name": "net_test_audio_hearing_aid_hw"
+ },
+ {
+ "name": "net_test_bluetooth"
+ },
+ {
+ "name": "net_test_bta"
+ },
+ {
+ "name": "net_test_bta_security"
+ },
+ {
+ "name": "net_test_btif"
+ },
+ {
+ "name": "net_test_btif_hf_client_service"
+ },
+ {
+ "name": "net_test_btif_profile_queue"
+ },
+ {
+ "name": "net_test_btif_avrcp_audio_track"
+ },
+ {
+ "name": "net_test_device"
+ },
+ {
+ "name": "net_test_device_iot_config"
+ },
+ {
+ "name": "net_test_conn_multiplexing"
+ },
+ {
+ "name": "net_test_hci"
+ },
+ {
+ "name": "net_test_stack"
+ },
+ {
+ "name": "net_test_stack_a2dp_codecs_native"
+ },
+ {
+ "name": "net_test_stack_ad_parser"
+ },
+ {
+ "name": "bluetooth_csis_test"
+ },
+ {
+ "name": "bluetooth_flatbuffer_tests"
+ },
+ {
+ "name": "bluetooth_groups_test"
+ },
+ {
+ "name": "bluetooth_has_test"
+ },
+ {
+ "name": "bluetooth_hh_test"
+ },
+ {
+ "name": "bluetooth_le_audio_client_test"
+ },
+ {
+ "name": "bluetooth_le_audio_test"
+ },
+ {
+ "name": "bluetooth_packet_parser_test"
+ },
+ {
+ "name": "bluetooth_test_broadcaster"
+ },
+ {
+ "name": "bluetooth_test_broadcaster_state_machine"
+ },
+ {
+ "name": "bluetooth_test_common"
+ },
+ {
+ "name": "bluetooth_vc_test"
+ },
+ {
+ "name": "libaptx_enc_tests"
+ },
+ {
+ "name": "libaptxhd_enc_tests"
+ },
+ {
+ "name": "net_test_avrcp"
+ },
+ {
+ "name": "net_test_btcore"
+ },
+ {
+ "name": "net_test_btif_hh"
+ },
+ {
+ "name": "net_test_btif_rc"
+ },
+ {
+ "name": "net_test_btif_stack"
+ },
+ {
+ "name": "net_test_btm_iso"
+ },
+ {
+ "name": "net_test_btpackets"
+ },
+ {
+ "name": "net_test_eatt"
+ },
+ {
+ "name": "net_test_main_shim"
+ },
+ {
+ "name": "net_test_osi"
+ },
+ {
+ "name": "net_test_performance"
+ },
+ {
+ "name": "net_test_stack_a2dp_native"
+ },
+ {
+ "name": "net_test_stack_acl"
+ },
+ {
+ "name": "net_test_stack_avdtp"
+ },
+ {
+ "name": "net_test_stack_btm"
+ },
+ {
+ "name": "net_test_stack_btu"
+ },
+ {
+ "name": "net_test_stack_gatt"
+ },
+ {
+ "name": "net_test_stack_gatt_native"
+ },
+ {
+ "name": "net_test_stack_gatt_sr_hash_native"
+ },
+ {
+ "name": "net_test_stack_hci"
+ },
+ {
+ "name": "net_test_stack_hid"
+ },
+ {
+ "name": "net_test_stack_l2cap"
+ },
+ {
+ "name": "net_test_stack_rfcomm"
+ },
+ {
+ "name": "net_test_stack_sdp"
+ },
+ {
+ "name": "net_test_stack_smp"
+ },
+ {
+ "name": "net_test_types"
+ }
+ ],
"presubmit": [
// android_test targets
{
diff --git a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java
index 1dc753318e..61b412f2f8 100644
--- a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java
+++ b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java
@@ -66,7 +66,6 @@ class DistanceMeasurementInitiator {
}
}
- private static final int DISTANCE_MEASUREMENT_DURATION_SEC = 3600;
private static final List<Pair<Integer, String>> mDistanceMeasurementMethodMapping =
List.of(
new Pair<>(DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_AUTO, "AUTO"),
@@ -151,8 +150,13 @@ class DistanceMeasurementInitiator {
return List.of(Freq.MEDIUM.toString(), Freq.HIGH.toString(), Freq.LOW.toString());
}
+ List<String> getMeasureDurationsInSeconds() {
+ return List.of("3600", "300", "60", "10");
+ }
+
@SuppressLint("MissingPermission") // permissions are checked upfront
- void startDistanceMeasurement(String distanceMeasurementMethodName, String selectedFreq) {
+ void startDistanceMeasurement(
+ String distanceMeasurementMethodName, String selectedFreq, int duration) {
if (mTargetDevice == null) {
printLog("do Gatt connect first");
@@ -163,7 +167,7 @@ class DistanceMeasurementInitiator {
DistanceMeasurementParams params =
new DistanceMeasurementParams.Builder(mTargetDevice)
- .setDurationSeconds(DISTANCE_MEASUREMENT_DURATION_SEC)
+ .setDurationSeconds(duration)
.setFrequency(Freq.fromName(selectedFreq).getFreq())
.setMethodId(getDistanceMeasurementMethodId(distanceMeasurementMethodName))
.build();
diff --git a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java
index b1b96d7bb1..cd26703e56 100644
--- a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java
+++ b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java
@@ -44,10 +44,12 @@ public class InitiatorFragment extends Fragment {
private ArrayAdapter<String> mDmMethodArrayAdapter;
private ArrayAdapter<String> mFreqArrayAdapter;
+ private ArrayAdapter<String> mDurationArrayAdapter;
private TextView mDistanceText;
private CanvasView mDistanceCanvasView;
private Spinner mSpinnerDmMethod;
private Spinner mSpinnerFreq;
+ private Spinner mSpinnerDuration;
private Button mButtonCs;
private LinearLayout mDistanceViewLayout;
private TextView mLogText;
@@ -66,6 +68,7 @@ public class InitiatorFragment extends Fragment {
mButtonCs = (Button) root.findViewById(R.id.btn_cs);
mSpinnerDmMethod = (Spinner) root.findViewById(R.id.spinner_dm_method);
mSpinnerFreq = (Spinner) root.findViewById(R.id.spinner_freq);
+ mSpinnerDuration = (Spinner) root.findViewById(R.id.spinner_duration);
mDistanceViewLayout = (LinearLayout) root.findViewById(R.id.layout_distance_view);
mDistanceText = new TextView(getContext());
mDistanceViewLayout.addView(mDistanceText);
@@ -93,6 +96,12 @@ public class InitiatorFragment extends Fragment {
getContext(), android.R.layout.simple_spinner_item, new ArrayList<>());
mFreqArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinnerFreq.setAdapter(mFreqArrayAdapter);
+ mDurationArrayAdapter =
+ new ArrayAdapter<String>(
+ getContext(), android.R.layout.simple_spinner_item, new ArrayList<>());
+ mDurationArrayAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ mSpinnerDuration.setAdapter(mDurationArrayAdapter);
mInitiatorViewModel = new ViewModelProvider(this).get(InitiatorViewModel.class);
mBleConnectionViewModel = new ViewModelProvider(this).get(BleConnectionViewModel.class);
@@ -143,14 +152,18 @@ public class InitiatorFragment extends Fragment {
mDmMethodArrayAdapter.addAll(mInitiatorViewModel.getSupportedDmMethods());
mFreqArrayAdapter.addAll(mInitiatorViewModel.getMeasurementFreqs());
+ mDurationArrayAdapter.addAll(mInitiatorViewModel.getMeasurementDurations());
mButtonCs.setOnClickListener(
v -> {
String methodName = mSpinnerDmMethod.getSelectedItem().toString();
String freq = mSpinnerFreq.getSelectedItem().toString();
+ int duration = Integer.parseInt(mSpinnerDuration.getSelectedItem().toString());
+
if (TextUtils.isEmpty(methodName)) {
printLog("the device doesn't support any distance measurement methods.");
}
- mInitiatorViewModel.toggleCsStartStop(methodName, freq);
+
+ mInitiatorViewModel.toggleCsStartStop(methodName, freq, duration);
});
}
diff --git a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java
index e07e7a1593..1203f9e488 100644
--- a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java
+++ b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java
@@ -75,10 +75,14 @@ public class InitiatorViewModel extends AndroidViewModel {
return mDistanceMeasurementInitiator.getMeasurementFreqs();
}
- void toggleCsStartStop(String distanceMeasurementMethodName, String freq) {
+ List<String> getMeasurementDurations() {
+ return mDistanceMeasurementInitiator.getMeasureDurationsInSeconds();
+ }
+
+ void toggleCsStartStop(String distanceMeasurementMethodName, String freq, int duration) {
if (!mCsStarted.getValue()) {
mDistanceMeasurementInitiator.startDistanceMeasurement(
- distanceMeasurementMethodName, freq);
+ distanceMeasurementMethodName, freq, duration);
} else {
mDistanceMeasurementInitiator.stopDistanceMeasurement();
}
diff --git a/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml b/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml
index 39b0246c05..78e17927fd 100644
--- a/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml
+++ b/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml
@@ -16,49 +16,81 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
- app:layout_constraintBottom_toTopOf="@id/spinner_dm_method"
+ app:layout_constraintBottom_toTopOf="@id/layout_methods"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <TextView
- android:id="@+id/dm_method_label"
- android:layout_width="wrap_content"
+ <LinearLayout android:id="@+id/layout_methods"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text= "Method"
- app:layout_constraintBottom_toTopOf="@id/btn_cs"
- app:layout_constraintEnd_toStartOf="@id/spinner_dm_method"
- app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container"
- />
- <Spinner
- android:id="@+id/spinner_dm_method"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:padding="10dp"
- app:layout_constraintEnd_toStartOf="@id/freq_label"
- app:layout_constraintStart_toEndOf="@id/dm_method_label"
- app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container" />
- <TextView
- android:id="@+id/freq_label"
- android:layout_width="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/layout_parameters"
+ android:weightSum="4"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/dm_method_label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.6"
+ android:text= "Method"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/spinner_dm_method"
+ />
+ <Spinner
+ android:id="@+id/spinner_dm_method"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.4"
+ android:padding="10dp"
+ app:layout_constraintStart_toEndOf="@id/dm_method_label"
+ app:layout_constraintEnd_toEndOf="parent"
+ />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/layout_parameters"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text= "Freq"
+ app:layout_constraintTop_toBottomOf="@id/layout_methods"
app:layout_constraintBottom_toTopOf="@id/btn_cs"
- app:layout_constraintEnd_toStartOf="@id/spinner_freq"
- app:layout_constraintStart_toEndOf="@id/spinner_dm_method"
- app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container"
- />
- <Spinner
- android:id="@+id/spinner_freq"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:padding="10dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@id/freq_label"
- app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container" />
+ android:weightSum="4"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/freq_label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.6"
+ android:text= "Freq"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/spinner_freq"
+ />
+ <Spinner
+ android:id="@+id/spinner_freq"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.4"
+ android:padding="10dp"
+ app:layout_constraintStart_toEndOf="@id/freq_label"
+ app:layout_constraintEnd_toStartOf="@id/duration_label"
+ />
+ <TextView
+ android:id="@+id/duration_label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.7"
+ android:text= "Duration (s)"
+ app:layout_constraintStart_toEndOf="@id/spinner_freq"
+ app:layout_constraintEnd_toStartOf="@id/spinner_duration"
+ />
+ <Spinner
+ android:id="@+id/spinner_duration"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.3"
+ android:padding="10dp"
+ app:layout_constraintStart_toEndOf="@id/duration_label"
+ app:layout_constraintEnd_toEndOf="parent"
+ />
+ </LinearLayout>
<Button
android:id="@+id/btn_cs"
android:layout_width="wrap_content"
@@ -69,7 +101,7 @@
android:text="Start Distance Measurement"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/spinner_dm_method" />
+ app:layout_constraintTop_toBottomOf="@id/layout_parameters" />
<TextView
android:id="@+id/text_log"
android:layout_width="match_parent"
diff --git a/android/app/Android.bp b/android/app/Android.bp
index 09d8a91865..db85914522 100644
--- a/android/app/Android.bp
+++ b/android/app/Android.bp
@@ -108,7 +108,6 @@ cc_library_shared {
"libaconfig_storage_read_api_cc",
"libbase",
"libbluetooth",
- "libbluetooth-dumpsys",
"libbluetooth-types",
"libbluetooth_core_rs",
"libbluetooth_core_rs_bridge",
diff --git a/android/app/OWNERS b/android/app/OWNERS
index 6f7b40e8f5..9edeffc18e 100644
--- a/android/app/OWNERS
+++ b/android/app/OWNERS
@@ -9,4 +9,3 @@ okamil@google.com
poahlo@google.com
siyuanh@google.com
wescande@google.com
-yuyangh@google.com
diff --git a/android/app/aidl/android/bluetooth/IBluetooth.aidl b/android/app/aidl/android/bluetooth/IBluetooth.aidl
index e619073fd9..158e37823f 100644
--- a/android/app/aidl/android/bluetooth/IBluetooth.aidl
+++ b/android/app/aidl/android/bluetooth/IBluetooth.aidl
@@ -31,6 +31,7 @@ import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevice.BluetoothAddress;
import android.bluetooth.BluetoothQualityReport;
import android.bluetooth.IncomingRfcommSocketInfo;
import android.bluetooth.OobData;
@@ -40,6 +41,8 @@ import android.os.ParcelUuid;
import android.os.ParcelFileDescriptor;
import android.os.ResultReceiver;
+parcelable BluetoothDevice.BluetoothAddress;
+
/**
* System private API for talking with the Bluetooth service.
*
@@ -63,6 +66,8 @@ interface IBluetooth
boolean setName(in String name, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
String getIdentityAddress(in String address);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ BluetoothDevice.BluetoothAddress getIdentityAddressWithType(in String address);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
String getName(in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)")
@@ -333,4 +338,10 @@ interface IBluetooth
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)")
oneway void killBluetoothProcess();
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)")
+ boolean isLeCocSocketOffloadSupported(in AttributionSource source);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)")
+ boolean isRfcommSocketOffloadSupported(in AttributionSource source);
}
diff --git a/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl b/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl
index f9436a7fa2..9b2de3e169 100644
--- a/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl
+++ b/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl
@@ -81,7 +81,7 @@ interface IBluetoothGatt {
void setAdvertisingData(in int advertiserId, in AdvertiseData data, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)")
void setScanResponseData(in int advertiserId, in AdvertiseData data, in AttributionSource attributionSource);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE,android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true)")
void setAdvertisingParameters(in int advertiserId, in AdvertisingSetParameters parameters, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)")
void setPeriodicAdvertisingParameters(in int advertiserId, in PeriodicAdvertisingParameters parameters, in AttributionSource attributionSource);
@@ -176,11 +176,8 @@ interface IBluetoothGatt {
void disconnectAll(in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)")
int numHwTrackFiltersAvailable(in AttributionSource attributionSource);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void leSubrateRequest(in int clientIf, in String address, in int subrateMin, in int subrateMax, in int maxLatency,
- in int contNumber, in int supervisionTimeout, in AttributionSource attributionSource);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void subrateModeRequest(in int clientIf, in String address, in int subrateMode, in AttributionSource attributionSource);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true)")
+ int subrateModeRequest(in int clientIf, in BluetoothDevice device, in int subrateMode, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
List<DistanceMeasurementMethod> getSupportedDistanceMeasurementMethods(in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
diff --git a/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl b/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl
index 1bbf692cda..05f647d4a9 100644
--- a/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl
+++ b/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl
@@ -29,8 +29,12 @@ interface IBluetoothSocketManager
{
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
@nullable ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in @nullable ParcelUuid uuid, int port, int flag);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ @nullable ParcelFileDescriptor connectSocketwithOffload(in BluetoothDevice device, int type, in @nullable ParcelUuid uuid, int port, int flag, int dataPath, in String socketName, long hubId, long endpointId, int maximumPacketSize);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
@nullable ParcelFileDescriptor createSocketChannel(int type, in @nullable String serviceName, in @nullable ParcelUuid uuid, int port, int flag);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ @nullable ParcelFileDescriptor createSocketChannelWithOffload(int type, in @nullable String serviceName, in @nullable ParcelUuid uuid, int port, int flag, int dataPath, in String socketName, long hubId, long endpointId, int maximumPacketSize);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void requestMaximumTxDataLength(in BluetoothDevice device);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
diff --git a/android/app/jni/com_android_bluetooth_a2dp.cpp b/android/app/jni/com_android_bluetooth_a2dp.cpp
index 2d6e255d15..df467e8427 100644
--- a/android/app/jni/com_android_bluetooth_a2dp.cpp
+++ b/android/app/jni/com_android_bluetooth_a2dp.cpp
@@ -36,15 +36,23 @@
#include "types/raw_address.h"
namespace android {
-static jmethodID method_onConnectionStateChanged;
-static jmethodID method_onAudioStateChanged;
-static jmethodID method_onCodecConfigChanged;
-static jmethodID method_isMandatoryCodecPreferred;
+
+static struct {
+ jfieldID mNativeCallback;
+} android_bluetooth_A2dpNativeInterface;
+
+static struct {
+ jmethodID onConnectionStateChanged;
+ jmethodID onAudioStateChanged;
+ jmethodID onCodecConfigChanged;
+ jmethodID isMandatoryCodecPreferred;
+} android_bluetooth_A2dpNativeCallback;
static struct {
jclass clazz;
jmethodID constructor;
jmethodID getCodecType;
+ jmethodID getExtendedCodecType;
jmethodID getCodecPriority;
jmethodID getSampleRate;
jmethodID getBitsPerSample;
@@ -55,6 +63,12 @@ static struct {
jmethodID getCodecSpecific4;
} android_bluetooth_BluetoothCodecConfig;
+static struct {
+ jclass clazz;
+ jmethodID constructor;
+ jmethodID getCodecId;
+} android_bluetooth_BluetoothCodecType;
+
static std::vector<btav_a2dp_codec_info_t> supported_codecs;
static std::shared_timed_mutex interface_mutex;
@@ -81,8 +95,9 @@ static void bta2dp_connection_state_callback(const RawAddress& bd_addr,
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
reinterpret_cast<const jbyte*>(bd_addr.address));
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, addr.get(),
- (jint)state);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj,
+ android_bluetooth_A2dpNativeCallback.onConnectionStateChanged,
+ addr.get(), (jint)state);
}
static void bta2dp_audio_state_callback(const RawAddress& bd_addr, btav_audio_state_t state) {
@@ -103,7 +118,9 @@ static void bta2dp_audio_state_callback(const RawAddress& bd_addr, btav_audio_st
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
reinterpret_cast<const jbyte*>(bd_addr.address));
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, addr.get(), (jint)state);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj,
+ android_bluetooth_A2dpNativeCallback.onAudioStateChanged, addr.get(),
+ (jint)state);
}
static void bta2dp_audio_config_callback(
@@ -168,9 +185,9 @@ static void bta2dp_audio_config_callback(
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, RawAddress::kLength,
reinterpret_cast<const jbyte*>(bd_addr.address));
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCodecConfigChanged, addr.get(),
- codecConfigObj, local_capabilities_array,
- selectable_capabilities_array);
+ sCallbackEnv->CallVoidMethod(
+ mCallbacksObj, android_bluetooth_A2dpNativeCallback.onCodecConfigChanged, addr.get(),
+ codecConfigObj, local_capabilities_array, selectable_capabilities_array);
}
static bool bta2dp_mandatory_codec_preferred_callback(const RawAddress& bd_addr) {
@@ -190,8 +207,9 @@ static bool bta2dp_mandatory_codec_preferred_callback(const RawAddress& bd_addr)
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, RawAddress::kLength,
reinterpret_cast<const jbyte*>(bd_addr.address));
- return sCallbackEnv->CallBooleanMethod(mCallbacksObj, method_isMandatoryCodecPreferred,
- addr.get());
+ return sCallbackEnv->CallBooleanMethod(
+ mCallbacksObj, android_bluetooth_A2dpNativeCallback.isMandatoryCodecPreferred,
+ addr.get());
}
static btav_source_callbacks_t sBluetoothA2dpCallbacks = {
@@ -216,6 +234,7 @@ static std::vector<btav_a2dp_codec_config_t> prepareCodecPreferences(
log::error("Invalid BluetoothCodecConfig instance");
continue;
}
+
jint codecType =
env->CallIntMethod(jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecType);
jint codecPriority = env->CallIntMethod(
@@ -268,7 +287,8 @@ static void initNative(JNIEnv* env, jobject object, jint maxConnectedAudioDevice
mCallbacksObj = nullptr;
}
- if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
+ if ((mCallbacksObj = env->NewGlobalRef(env->GetObjectField(
+ object, android_bluetooth_A2dpNativeInterface.mNativeCallback))) == nullptr) {
log::error("Failed to allocate Global Ref for A2DP Callbacks");
return;
}
@@ -280,6 +300,13 @@ static void initNative(JNIEnv* env, jobject object, jint maxConnectedAudioDevice
return;
}
+ android_bluetooth_BluetoothCodecType.clazz =
+ (jclass)env->NewGlobalRef(env->FindClass("android/bluetooth/BluetoothCodecType"));
+ if (android_bluetooth_BluetoothCodecType.clazz == nullptr) {
+ log::error("Failed to allocate Global Ref for BluetoothCodecType class");
+ return;
+ }
+
std::vector<btav_a2dp_codec_config_t> codec_priorities =
prepareCodecPreferences(env, object, codecConfigArray);
@@ -316,23 +343,8 @@ static void cleanupNative(JNIEnv* env, jobject /* object */) {
}
static jobjectArray getSupportedCodecTypesNative(JNIEnv* env) {
- jclass android_bluetooth_BluetoothCodecType_clazz =
- (jclass)env->NewGlobalRef(env->FindClass("android/bluetooth/BluetoothCodecType"));
- if (android_bluetooth_BluetoothCodecType_clazz == nullptr) {
- log::error("Failed to allocate Global Ref for BluetoothCodecType class");
- return nullptr;
- }
-
- jmethodID init = env->GetMethodID(android_bluetooth_BluetoothCodecType_clazz, "<init>",
- "(IJLjava/lang/String;)V");
-
- if (init == nullptr) {
- log::error("Failed to find method <init> of BluetoothCodecType class");
- return nullptr;
- }
-
jobjectArray result = env->NewObjectArray(supported_codecs.size(),
- android_bluetooth_BluetoothCodecType_clazz, nullptr);
+ android_bluetooth_BluetoothCodecType.clazz, nullptr);
if (result == nullptr) {
log::error("Failed to allocate result array of BluetoothCodecType");
@@ -341,7 +353,8 @@ static jobjectArray getSupportedCodecTypesNative(JNIEnv* env) {
for (size_t index = 0; index < supported_codecs.size(); index++) {
jobject codec_type = env->NewObject(
- android_bluetooth_BluetoothCodecType_clazz, init,
+ android_bluetooth_BluetoothCodecType.clazz,
+ android_bluetooth_BluetoothCodecType.constructor,
(jint)supported_codecs[index].codec_type, (jlong)supported_codecs[index].codec_id,
env->NewStringUTF(supported_codecs[index].codec_name.c_str()));
env->SetObjectArrayElement(result, index, codec_type);
@@ -443,6 +456,7 @@ static jboolean setCodecConfigPreferenceNative(JNIEnv* env, jobject object, jbyt
bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
std::vector<btav_a2dp_codec_config_t> codec_preferences =
prepareCodecPreferences(env, object, codecConfigArray);
+
log::info("{}: {}", bd_addr, btav_a2dp_codec_config_t::PrintCodecs(codec_preferences));
bt_status_t status = btif_av_source_set_codec_config_preference(bd_addr, codec_preferences);
if (status != BT_STATUS_SUCCESS) {
@@ -475,20 +489,32 @@ int register_com_android_bluetooth_a2dp(JNIEnv* env) {
}
const JNIJavaMethod javaMethods[] = {
- {"onConnectionStateChanged", "([BI)V", &method_onConnectionStateChanged},
- {"onAudioStateChanged", "([BI)V", &method_onAudioStateChanged},
+ {"onConnectionStateChanged", "([BI)V",
+ &android_bluetooth_A2dpNativeCallback.onConnectionStateChanged},
+ {"onAudioStateChanged", "([BI)V",
+ &android_bluetooth_A2dpNativeCallback.onAudioStateChanged},
{"onCodecConfigChanged",
"([BLandroid/bluetooth/BluetoothCodecConfig;"
"[Landroid/bluetooth/BluetoothCodecConfig;"
"[Landroid/bluetooth/BluetoothCodecConfig;)V",
- &method_onCodecConfigChanged},
- {"isMandatoryCodecPreferred", "([B)Z", &method_isMandatoryCodecPreferred},
+ &android_bluetooth_A2dpNativeCallback.onCodecConfigChanged},
+ {"isMandatoryCodecPreferred", "([B)Z",
+ &android_bluetooth_A2dpNativeCallback.isMandatoryCodecPreferred},
};
- GET_JAVA_METHODS(env, "com/android/bluetooth/a2dp/A2dpNativeInterface", javaMethods);
+ GET_JAVA_METHODS(env, "com/android/bluetooth/a2dp/A2dpNativeCallback", javaMethods);
+
+ jclass jniA2dpNativeInterfaceClass =
+ env->FindClass("com/android/bluetooth/a2dp/A2dpNativeInterface");
+ android_bluetooth_A2dpNativeInterface.mNativeCallback =
+ env->GetFieldID(jniA2dpNativeInterfaceClass, "mNativeCallback",
+ "Lcom/android/bluetooth/a2dp/A2dpNativeCallback;");
+ env->DeleteLocalRef(jniA2dpNativeInterfaceClass);
const JNIJavaMethod codecConfigCallbacksMethods[] = {
{"<init>", "(IIIIIJJJJ)V", &android_bluetooth_BluetoothCodecConfig.constructor},
{"getCodecType", "()I", &android_bluetooth_BluetoothCodecConfig.getCodecType},
+ {"getExtendedCodecType", "()Landroid/bluetooth/BluetoothCodecType;",
+ &android_bluetooth_BluetoothCodecConfig.getExtendedCodecType},
{"getCodecPriority", "()I", &android_bluetooth_BluetoothCodecConfig.getCodecPriority},
{"getSampleRate", "()I", &android_bluetooth_BluetoothCodecConfig.getSampleRate},
{"getBitsPerSample", "()I", &android_bluetooth_BluetoothCodecConfig.getBitsPerSample},
@@ -500,6 +526,12 @@ int register_com_android_bluetooth_a2dp(JNIEnv* env) {
};
GET_JAVA_METHODS(env, "android/bluetooth/BluetoothCodecConfig", codecConfigCallbacksMethods);
+ const JNIJavaMethod bluetoothCodecTypeMethods[] = {
+ {"<init>", "(IJLjava/lang/String;)V", &android_bluetooth_BluetoothCodecType.constructor},
+ {"getCodecId", "()J", &android_bluetooth_BluetoothCodecType.getCodecId},
+ };
+ GET_JAVA_METHODS(env, "android/bluetooth/BluetoothCodecType", bluetoothCodecTypeMethods);
+
return 0;
}
} // namespace android
diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 3a0a8d1aac..805e22b0df 100644
--- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -1782,11 +1782,14 @@ static jboolean setBufferLengthMillisNative(JNIEnv* /* env */, jobject /* obj */
}
static jint connectSocketNative(JNIEnv* env, jobject /* obj */, jbyteArray address, jint type,
- jbyteArray uuid, jint port, jint flag, jint callingUid) {
+ jbyteArray uuid, jint port, jint flag, jint callingUid,
+ jint dataPath, jstring socketName, jlong hubId, jlong endPointId,
+ jint maxRxPacketSize) {
int socket_fd = INVALID_FD;
jbyte* addr = nullptr;
jbyte* uuidBytes = nullptr;
Uuid btUuid;
+ const char* nativeSocketName = nullptr;
if (!sBluetoothSocketInterface) {
goto done;
@@ -1799,9 +1802,13 @@ static jint connectSocketNative(JNIEnv* env, jobject /* obj */, jbyteArray addre
}
btUuid = Uuid::From128BitBE(reinterpret_cast<uint8_t*>(uuidBytes));
+ if (socketName != nullptr) {
+ nativeSocketName = env->GetStringUTFChars(socketName, nullptr);
+ }
if (sBluetoothSocketInterface->connect(reinterpret_cast<RawAddress*>(addr), (btsock_type_t)type,
- &btUuid, port, &socket_fd, flag,
- callingUid) != BT_STATUS_SUCCESS) {
+ &btUuid, port, &socket_fd, flag, callingUid,
+ (btsock_data_path_t)dataPath, nativeSocketName, hubId,
+ endPointId, maxRxPacketSize) != BT_STATUS_SUCCESS) {
socket_fd = INVALID_FD;
}
@@ -1812,16 +1819,21 @@ done:
if (uuidBytes) {
env->ReleaseByteArrayElements(uuid, uuidBytes, 0);
}
+ if (nativeSocketName) {
+ env->ReleaseStringUTFChars(socketName, nativeSocketName);
+ }
return socket_fd;
}
static jint createSocketChannelNative(JNIEnv* env, jobject /* obj */, jint type,
jstring serviceName, jbyteArray uuid, jint port, jint flag,
- jint callingUid) {
+ jint callingUid, jint dataPath, jstring socketName,
+ jlong hubId, jlong endPointId, jint maxRxPacketSize) {
int socket_fd = INVALID_FD;
jbyte* uuidBytes = nullptr;
Uuid btUuid;
const char* nativeServiceName = nullptr;
+ const char* nativeSocketName = nullptr;
if (!sBluetoothSocketInterface) {
goto done;
@@ -1835,9 +1847,14 @@ static jint createSocketChannelNative(JNIEnv* env, jobject /* obj */, jint type,
goto done;
}
btUuid = Uuid::From128BitBE(reinterpret_cast<uint8_t*>(uuidBytes));
+ if (socketName != nullptr) {
+ nativeSocketName = env->GetStringUTFChars(socketName, nullptr);
+ }
if (sBluetoothSocketInterface->listen((btsock_type_t)type, nativeServiceName, &btUuid, port,
- &socket_fd, flag, callingUid) != BT_STATUS_SUCCESS) {
+ &socket_fd, flag, callingUid, (btsock_data_path_t)dataPath,
+ nativeSocketName, hubId, endPointId,
+ maxRxPacketSize) != BT_STATUS_SUCCESS) {
socket_fd = INVALID_FD;
}
@@ -1848,6 +1865,9 @@ done:
if (nativeServiceName) {
env->ReleaseStringUTFChars(serviceName, nativeServiceName);
}
+ if (nativeSocketName) {
+ env->ReleaseStringUTFChars(socketName, nativeSocketName);
+ }
return socket_fd;
}
@@ -2267,8 +2287,9 @@ int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
{"setBufferLengthMillisNative", "(II)Z",
reinterpret_cast<void*>(setBufferLengthMillisNative)},
{"getMetricIdNative", "([B)I", reinterpret_cast<void*>(getMetricIdNative)},
- {"connectSocketNative", "([BI[BIII)I", reinterpret_cast<void*>(connectSocketNative)},
- {"createSocketChannelNative", "(ILjava/lang/String;[BIII)I",
+ {"connectSocketNative", "([BI[BIIIILjava/lang/String;JJI)I",
+ reinterpret_cast<void*>(connectSocketNative)},
+ {"createSocketChannelNative", "(ILjava/lang/String;[BIIIILjava/lang/String;JJI)I",
reinterpret_cast<void*>(createSocketChannelNative)},
{"requestMaximumTxDataLengthNative", "([B)V",
reinterpret_cast<void*>(requestMaximumTxDataLengthNative)},
diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp
index 54e97282a1..80e334e844 100644
--- a/android/app/jni/com_android_bluetooth_gatt.cpp
+++ b/android/app/jni/com_android_bluetooth_gatt.cpp
@@ -247,28 +247,6 @@ void btgattc_register_app_cb(int status, int clientIf, const Uuid& app_uuid) {
UUID_PARAMS(app_uuid));
}
-void btgattc_scan_result_cb(uint16_t event_type, uint8_t addr_type, 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,
- std::vector<uint8_t> adv_data, RawAddress* original_bda) {
- std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
- CallbackEnv sCallbackEnv(__func__);
- if (!sCallbackEnv.valid() || !mScanCallbacksObj) {
- return;
- }
-
- ScopedLocalRef<jstring> address(sCallbackEnv.get(), bdaddr2newjstr(sCallbackEnv.get(), bda));
- ScopedLocalRef<jbyteArray> jb(sCallbackEnv.get(), sCallbackEnv->NewByteArray(adv_data.size()));
- sCallbackEnv->SetByteArrayRegion(jb.get(), 0, adv_data.size(), (jbyte*)adv_data.data());
-
- ScopedLocalRef<jstring> original_address(sCallbackEnv.get(),
- bdaddr2newjstr(sCallbackEnv.get(), original_bda));
-
- sCallbackEnv->CallVoidMethod(mScanCallbacksObj, method_onScanResult, event_type, addr_type,
- address.get(), primary_phy, secondary_phy, advertising_sid, tx_power,
- rssi, periodic_adv_int, jb.get(), original_address.get());
-}
-
void btgattc_open_cb(int conn_id, int status, int clientIf, const RawAddress& bda) {
std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
@@ -442,65 +420,6 @@ void btgattc_congestion_cb(int conn_id, bool congested) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientCongestion, conn_id, congested);
}
-void btgattc_batchscan_reports_cb(int client_if, int status, int report_format, int num_records,
- std::vector<uint8_t> data) {
- std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
- CallbackEnv sCallbackEnv(__func__);
- if (!sCallbackEnv.valid() || !mScanCallbacksObj) {
- return;
- }
- ScopedLocalRef<jbyteArray> jb(sCallbackEnv.get(), sCallbackEnv->NewByteArray(data.size()));
- sCallbackEnv->SetByteArrayRegion(jb.get(), 0, data.size(), (jbyte*)data.data());
-
- sCallbackEnv->CallVoidMethod(mScanCallbacksObj, method_onBatchScanReports, status, client_if,
- report_format, num_records, jb.get());
-}
-
-void btgattc_batchscan_threshold_cb(int client_if) {
- std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
- CallbackEnv sCallbackEnv(__func__);
- if (!sCallbackEnv.valid() || !mScanCallbacksObj) {
- return;
- }
- sCallbackEnv->CallVoidMethod(mScanCallbacksObj, method_onBatchScanThresholdCrossed, client_if);
-}
-
-void btgattc_track_adv_event_cb(btgatt_track_adv_info_t* p_adv_track_info) {
- std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
- CallbackEnv sCallbackEnv(__func__);
- if (!sCallbackEnv.valid() || !mScanCallbacksObj) {
- return;
- }
-
- ScopedLocalRef<jstring> address(sCallbackEnv.get(),
- bdaddr2newjstr(sCallbackEnv.get(), &p_adv_track_info->bd_addr));
-
- ScopedLocalRef<jbyteArray> jb_adv_pkt(sCallbackEnv.get(),
- sCallbackEnv->NewByteArray(p_adv_track_info->adv_pkt_len));
- ScopedLocalRef<jbyteArray> jb_scan_rsp(
- sCallbackEnv.get(), sCallbackEnv->NewByteArray(p_adv_track_info->scan_rsp_len));
-
- sCallbackEnv->SetByteArrayRegion(jb_adv_pkt.get(), 0, p_adv_track_info->adv_pkt_len,
- (jbyte*)p_adv_track_info->p_adv_pkt_data);
-
- sCallbackEnv->SetByteArrayRegion(jb_scan_rsp.get(), 0, p_adv_track_info->scan_rsp_len,
- (jbyte*)p_adv_track_info->p_scan_rsp_data);
-
- ScopedLocalRef<jobject> trackadv_obj(
- sCallbackEnv.get(),
- sCallbackEnv->CallObjectMethod(
- mScanCallbacksObj, method_createOnTrackAdvFoundLostObject,
- p_adv_track_info->client_if, p_adv_track_info->adv_pkt_len, jb_adv_pkt.get(),
- p_adv_track_info->scan_rsp_len, jb_scan_rsp.get(), p_adv_track_info->filt_index,
- p_adv_track_info->advertiser_state, p_adv_track_info->advertiser_info_present,
- address.get(), p_adv_track_info->addr_type, p_adv_track_info->tx_power,
- p_adv_track_info->rssi_value, p_adv_track_info->time_stamp));
-
- if (NULL != trackadv_obj.get()) {
- sCallbackEnv->CallVoidMethod(mScanCallbacksObj, method_onTrackAdvFoundLost, trackadv_obj.get());
- }
-}
-
void fillGattDbElementArray(JNIEnv* env, jobject* array, const btgatt_db_element_t* db, int count) {
// Because JNI uses a different class loader in the callback context, we
// cannot simply get the class.
@@ -628,13 +547,6 @@ void btgattc_subrate_change_cb(int conn_id, uint16_t subrate_factor, uint16_t la
latency, cont_num, timeout, status);
}
-static const btgatt_scanner_callbacks_t sGattScannerCallbacks = {
- btgattc_scan_result_cb,
- btgattc_batchscan_reports_cb,
- btgattc_batchscan_threshold_cb,
- btgattc_track_adv_event_cb,
-};
-
static const btgatt_client_callbacks_t sGattClientCallbacks = {
btgattc_register_app_cb,
btgattc_open_cb,
@@ -919,7 +831,6 @@ static const btgatt_callbacks_t sGattCallbacks = {
sizeof(btgatt_callbacks_t),
&sGattClientCallbacks,
&sGattServerCallbacks,
- &sGattScannerCallbacks,
};
class JniAdvertisingCallbacks : AdvertisingCallbacks {
@@ -2046,14 +1957,16 @@ static void gattConnectionParameterUpdateNative(JNIEnv* env, jobject /* object *
(uint16_t)max_ce_len);
}
-static void gattSubrateRequestNative(JNIEnv* env, jobject /* object */, jint /* client_if */,
- jstring address, jint subrate_min, jint subrate_max,
- jint max_latency, jint cont_num, jint sup_timeout) {
+static int gattSubrateRequestNative(JNIEnv* env, jobject /* object */, jint /* client_if */,
+ jstring address, jint subrate_min, jint subrate_max,
+ jint max_latency, jint cont_num, jint sup_timeout) {
if (!sGattIf) {
- return;
+ return 1; // BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
}
+ // TODO does bt_status_t align with BluetoothStatusCodes ?
sGattIf->client->subrate_request(str2addr(env, address), subrate_min, subrate_max, max_latency,
cont_num, sup_timeout);
+ return 0; // BluetoothStatusCodes.SUCCESS
}
void batchscan_cfg_storage_cb(uint8_t client_if, uint8_t status) {
@@ -3060,7 +2973,7 @@ static int register_com_android_bluetooth_gatt_(JNIEnv* env) {
{"gattServerSendIndicationNative", "(III[B)V", (void*)gattServerSendIndicationNative},
{"gattServerSendNotificationNative", "(III[B)V", (void*)gattServerSendNotificationNative},
{"gattServerSendResponseNative", "(IIIIII[BI)V", (void*)gattServerSendResponseNative},
- {"gattSubrateRequestNative", "(ILjava/lang/String;IIIII)V",
+ {"gattSubrateRequestNative", "(ILjava/lang/String;IIIII)I",
(void*)gattSubrateRequestNative},
{"gattTestNative", "(IJJLjava/lang/String;IIIII)V", (void*)gattTestNative},
diff --git a/android/app/jni/com_android_bluetooth_le_audio.cpp b/android/app/jni/com_android_bluetooth_le_audio.cpp
index 4ce436e5c4..3a3d8ceed6 100644
--- a/android/app/jni/com_android_bluetooth_le_audio.cpp
+++ b/android/app/jni/com_android_bluetooth_le_audio.cpp
@@ -706,7 +706,7 @@ static void setUnicastMonitorModeNative(JNIEnv* /* env */, jobject /* object */,
sLeAudioClientInterface->SetUnicastMonitorMode(direction, enable);
}
-static void sendAudioProfilePreferencesNative(JNIEnv* /* env */, jint groupId,
+static void sendAudioProfilePreferencesNative(JNIEnv* /* env */, jobject /* object */, jint groupId,
jboolean isOutputPreferenceLeAudio,
jboolean isDuplexPreferenceLeAudio) {
std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
diff --git a/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java b/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java
index f6d065eb76..e73c4f99ba 100644
--- a/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java
+++ b/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java
@@ -100,7 +100,13 @@ public class BluetoothMethodProxy {
final String selection,
final String[] selectionArgs,
final String sortOrder) {
- return contentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder);
+ try {
+ return contentResolver.query(
+ contentUri, projection, selection, selectionArgs, sortOrder);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception happened" + e + "\n" + Log.getStackTraceString(new Throwable()));
+ return null;
+ }
}
/** Proxies {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}. */
@@ -110,7 +116,12 @@ public class BluetoothMethodProxy {
final String[] projection,
final Bundle queryArgs,
final CancellationSignal cancellationSignal) {
- return contentResolver.query(contentUri, projection, queryArgs, cancellationSignal);
+ try {
+ return contentResolver.query(contentUri, projection, queryArgs, cancellationSignal);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception happened " + e + "\n" + Log.getStackTraceString(new Throwable()));
+ return null;
+ }
}
/** Proxies {@link ContentResolver#insert(Uri, ContentValues)}. */
diff --git a/android/app/src/com/android/bluetooth/Utils.java b/android/app/src/com/android/bluetooth/Utils.java
index 663227f899..ca897af46e 100644
--- a/android/app/src/com/android/bluetooth/Utils.java
+++ b/android/app/src/com/android/bluetooth/Utils.java
@@ -1290,7 +1290,11 @@ public final class Utils {
long elapsedRealtime();
}
- public static final TimeProvider sSystemClock = new SystemClockTimeProvider();
+ private static final TimeProvider sSystemClock = new SystemClockTimeProvider();
+
+ public static TimeProvider getSystemClock() {
+ return sSystemClock;
+ }
private static final class SystemClockTimeProvider implements TimeProvider {
@Override
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpNativeCallback.java b/android/app/src/com/android/bluetooth/a2dp/A2dpNativeCallback.java
new file mode 100644
index 0000000000..4ea0fbe96e
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpNativeCallback.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.a2dp;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+import android.util.Log;
+
+import com.android.bluetooth.btservice.AdapterService;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+class A2dpNativeCallback {
+ static final String TAG = A2dpNativeCallback.class.getSimpleName();
+
+ private final AdapterService mAdapterService;
+ private final A2dpService mA2dpService;
+
+ @VisibleForTesting
+ A2dpNativeCallback(@NonNull AdapterService adapterService, @NonNull A2dpService a2dpService) {
+ mAdapterService = requireNonNull(adapterService);
+ mA2dpService = requireNonNull(a2dpService);
+ }
+
+ private BluetoothDevice getDevice(byte[] address) {
+ return mAdapterService.getDeviceFromByte(address);
+ }
+
+ @VisibleForTesting
+ void onConnectionStateChanged(byte[] address, int state) {
+ A2dpStackEvent event =
+ new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.device = getDevice(address);
+ event.valueInt = state;
+
+ Log.d(TAG, "onConnectionStateChanged: " + event);
+ mA2dpService.messageFromNative(event);
+ }
+
+ @VisibleForTesting
+ void onAudioStateChanged(byte[] address, int state) {
+ A2dpStackEvent event = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
+ event.device = getDevice(address);
+ event.valueInt = state;
+
+ Log.d(TAG, "onAudioStateChanged: " + event);
+ mA2dpService.messageFromNative(event);
+ }
+
+ @VisibleForTesting
+ void onCodecConfigChanged(
+ byte[] address,
+ BluetoothCodecConfig newCodecConfig,
+ BluetoothCodecConfig[] codecsLocalCapabilities,
+ BluetoothCodecConfig[] codecsSelectableCapabilities) {
+ A2dpStackEvent event = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CODEC_CONFIG_CHANGED);
+ event.device = getDevice(address);
+ event.codecStatus =
+ new BluetoothCodecStatus(
+ newCodecConfig,
+ Arrays.asList(codecsLocalCapabilities),
+ Arrays.asList(codecsSelectableCapabilities));
+
+ Log.d(TAG, "onCodecConfigChanged: " + event);
+ mA2dpService.messageFromNative(event);
+ }
+
+ @VisibleForTesting
+ boolean isMandatoryCodecPreferred(byte[] address) {
+ int enabled = mA2dpService.getOptionalCodecsEnabled(getDevice(address));
+
+ Log.d(TAG, "isMandatoryCodecPreferred: optional preference " + enabled);
+ return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java b/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java
index 2de9f0d8fa..709dc954c5 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java
@@ -21,65 +21,37 @@
*/
package com.android.bluetooth.a2dp;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
import android.bluetooth.BluetoothCodecConfig;
-import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothCodecType;
import android.bluetooth.BluetoothDevice;
-import android.util.Log;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.flags.Flags;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.lang.annotation.Native;
+
import java.util.Arrays;
import java.util.List;
-import java.util.Objects;
/** A2DP Native Interface to/from JNI. */
public class A2dpNativeInterface {
private static final String TAG = A2dpNativeInterface.class.getSimpleName();
- private BluetoothAdapter mAdapter;
- private AdapterService mAdapterService;
- @GuardedBy("INSTANCE_LOCK")
- private static A2dpNativeInterface sInstance;
+ private final AdapterService mAdapterService;
+ @Native private final A2dpNativeCallback mNativeCallback;
- private static BluetoothCodecType[] sSupportedCodecTypes;
-
- private static final Object INSTANCE_LOCK = new Object();
+ private BluetoothCodecType[] mSupportedCodecTypes;
@VisibleForTesting
- private A2dpNativeInterface() {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- if (mAdapter == null) {
- Log.wtf(TAG, "No Bluetooth Adapter Available");
- }
- mAdapterService =
- Objects.requireNonNull(
- AdapterService.getAdapterService(),
- "AdapterService cannot be null when A2dpNativeInterface init");
- }
-
- /** Get singleton instance. */
- public static A2dpNativeInterface getInstance() {
- synchronized (INSTANCE_LOCK) {
- if (sInstance == null) {
- sInstance = new A2dpNativeInterface();
- }
- return sInstance;
- }
- }
-
- /** Set singleton instance. */
- @VisibleForTesting
- public static void setInstance(A2dpNativeInterface instance) {
- synchronized (INSTANCE_LOCK) {
- sInstance = instance;
- }
+ A2dpNativeInterface(
+ @NonNull AdapterService adapterService, @NonNull A2dpNativeCallback nativeCallback) {
+ mAdapterService = requireNonNull(adapterService);
+ mNativeCallback = requireNonNull(nativeCallback);
}
/**
@@ -103,10 +75,10 @@ public class A2dpNativeInterface {
/** Returns the list of locally supported codec types. */
public List<BluetoothCodecType> getSupportedCodecTypes() {
- if (sSupportedCodecTypes == null) {
- sSupportedCodecTypes = getSupportedCodecTypesNative();
+ if (mSupportedCodecTypes == null) {
+ mSupportedCodecTypes = getSupportedCodecTypesNative();
}
- return Arrays.asList(sSupportedCodecTypes);
+ return Arrays.asList(mSupportedCodecTypes);
}
/**
@@ -161,10 +133,6 @@ public class A2dpNativeInterface {
return setCodecConfigPreferenceNative(getByteAddress(device), codecConfigArray);
}
- private BluetoothDevice getDevice(byte[] address) {
- return mAdapterService.getDeviceFromByte(address);
- }
-
private byte[] getByteAddress(BluetoothDevice device) {
if (device == null) {
return Utils.getBytesFromAddress("00:00:00:00:00:00");
@@ -176,68 +144,6 @@ public class A2dpNativeInterface {
}
}
- private void sendMessageToService(A2dpStackEvent event) {
- A2dpService service = A2dpService.getA2dpService();
- if (service != null) {
- service.messageFromNative(event);
- } else {
- Log.w(TAG, "Event ignored, service not available: " + event);
- }
- }
-
- // Callbacks from the native stack back into the Java framework.
- // All callbacks are routed via the Service which will disambiguate which
- // state machine the message should be routed to.
-
- private void onConnectionStateChanged(byte[] address, int state) {
- A2dpStackEvent event =
- new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
- event.device = getDevice(address);
- event.valueInt = state;
-
- Log.d(TAG, "onConnectionStateChanged: " + event);
- sendMessageToService(event);
- }
-
- private void onAudioStateChanged(byte[] address, int state) {
- A2dpStackEvent event = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
- event.device = getDevice(address);
- event.valueInt = state;
-
- Log.d(TAG, "onAudioStateChanged: " + event);
- sendMessageToService(event);
- }
-
- private void onCodecConfigChanged(
- byte[] address,
- BluetoothCodecConfig newCodecConfig,
- BluetoothCodecConfig[] codecsLocalCapabilities,
- BluetoothCodecConfig[] codecsSelectableCapabilities) {
- A2dpStackEvent event = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CODEC_CONFIG_CHANGED);
- event.device = getDevice(address);
- event.codecStatus =
- new BluetoothCodecStatus(
- newCodecConfig,
- Arrays.asList(codecsLocalCapabilities),
- Arrays.asList(codecsSelectableCapabilities));
- Log.d(TAG, "onCodecConfigChanged: " + event);
- sendMessageToService(event);
- }
-
- private boolean isMandatoryCodecPreferred(byte[] address) {
- A2dpService service = A2dpService.getA2dpService();
- if (service != null) {
- int enabled = service.getOptionalCodecsEnabled(getDevice(address));
- Log.d(TAG, "isMandatoryCodecPreferred: optional preference " + enabled);
- // Optional codecs are more preferred if possible
- return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
- } else {
- Log.w(TAG, "isMandatoryCodecPreferred: service not available");
- return false;
- }
- }
-
- // Native methods that call into the JNI interface
private native void initNative(
int maxConnectedAudioDevices,
BluetoothCodecConfig[] codecConfigPriorities,
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
index 355cb36929..136a0d4621 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -24,6 +24,7 @@ import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static com.android.bluetooth.Utils.checkCallerTargetSdk;
import static java.util.Objects.requireNonNull;
+import static java.util.Objects.requireNonNullElseGet;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
@@ -92,7 +93,6 @@ public class A2dpService extends ProfileService {
private final CompanionDeviceManager mCompanionDeviceManager;
private final Looper mLooper;
private final Handler mHandler;
- private final HandlerThread mStateMachinesThread;
// Upper limit of all A2DP devices that are Connected or Connecting
private final int mMaxConnectedAudioDevices;
@@ -108,9 +108,6 @@ public class A2dpService extends ProfileService {
// Protect setActiveDevice()/removeActiveDevice() so all invoked is handled sequentially
private final Object mActiveSwitchingGuard = new Object();
- // Timeout for state machine thread join, to prevent potential ANR.
- private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000;
-
// Upper limit of all A2DP devices: Bonded or Connected
private static final int MAX_A2DP_STATE_MACHINES = 50;
// A2DP Offload Enabled in platform
@@ -120,14 +117,20 @@ public class A2dpService extends ProfileService {
new AudioManagerAudioDeviceCallback();
public A2dpService(AdapterService adapterService) {
- this(adapterService, A2dpNativeInterface.getInstance(), Looper.getMainLooper());
+ this(adapterService, null, Looper.getMainLooper());
}
@VisibleForTesting
A2dpService(AdapterService adapterService, A2dpNativeInterface nativeInterface, Looper looper) {
super(requireNonNull(adapterService));
mAdapterService = adapterService;
- mNativeInterface = requireNonNull(nativeInterface);
+ mNativeInterface =
+ requireNonNullElseGet(
+ nativeInterface,
+ () ->
+ new A2dpNativeInterface(
+ adapterService,
+ new A2dpNativeCallback(adapterService, this)));
mDatabaseManager = requireNonNull(mAdapterService.getDatabase());
mAudioManager = requireNonNull(getSystemService(AudioManager.class));
mCompanionDeviceManager = requireNonNull(getSystemService(CompanionDeviceManager.class));
@@ -137,13 +140,6 @@ public class A2dpService extends ProfileService {
mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
Log.i(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices);
- if (!Flags.a2dpServiceLooper()) {
- mStateMachinesThread = new HandlerThread("A2dpService.StateMachines");
- mStateMachinesThread.start();
- } else {
- mStateMachinesThread = null;
- }
-
mA2dpCodecConfig = new A2dpCodecConfig(this, mNativeInterface);
mNativeInterface.init(
@@ -200,15 +196,6 @@ public class A2dpService extends ProfileService {
mStateMachines.clear();
}
- if (mStateMachinesThread != null) {
- try {
- mStateMachinesThread.quitSafely();
- mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS);
- } catch (InterruptedException e) {
- // Do not rethrow as we are shutting down anyway
- }
- }
-
mHandler.removeCallbacksAndMessages(null);
}
@@ -899,9 +886,12 @@ public class A2dpService extends ProfileService {
// Handle messages from native (JNI) to Java
void messageFromNative(A2dpStackEvent stackEvent) {
- requireNonNull(stackEvent.device);
+ if (!isAvailable()) {
+ Log.w(TAG, "messageFromNative(): service is not available");
+ return;
+ }
+ BluetoothDevice device = requireNonNull(stackEvent.device);
synchronized (mStateMachines) {
- BluetoothDevice device = stackEvent.device;
A2dpStateMachine sm = mStateMachines.get(device);
if (sm == null) {
if (stackEvent.type == A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
@@ -1015,7 +1005,7 @@ public class A2dpService extends ProfileService {
device,
mNativeInterface,
mA2dpOffloadEnabled,
- Flags.a2dpServiceLooper() ? mLooper : mStateMachinesThread.getLooper());
+ mLooper);
mStateMachines.put(device, sm);
return sm;
}
@@ -1170,7 +1160,12 @@ public class A2dpService extends ProfileService {
if (sm == null) {
return;
}
- if (sm.getConnectionState() != BluetoothProfile.STATE_DISCONNECTED) {
+
+ // Bond removal implies that the ACL is disconnected and device properties are removed.
+ // If pseudo address is not same as the identity address, all further events from the
+ // native stack would get ignored. So the state machine must be removed right away.
+ if (!Flags.a2dpCleanupOnRemoveDevice()
+ && sm.getConnectionState() != BluetoothProfile.STATE_DISCONNECTED) {
return;
}
}
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index f0b5a028ac..a2e4d0b4d2 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -328,7 +328,14 @@ final class A2dpStateMachine extends StateMachine {
+ messageWhatToString(message.what));
switch (message.what) {
- case MESSAGE_CONNECT -> deferMessage(message);
+ case MESSAGE_CONNECT -> {
+ if (Flags.a2dpSmIgnoreConnectEventsInConnectingState()
+ && !hasDeferredMessages(MESSAGE_DISCONNECT)) {
+ Log.w(TAG, "Connecting: CONNECT ignored: " + mDevice);
+ } else {
+ deferMessage(message);
+ }
+ }
case MESSAGE_CONNECT_TIMEOUT -> {
Log.w(TAG, "Connecting connection timeout: " + mDevice);
mA2dpNativeInterface.disconnectA2dp(mDevice);
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 e9e0f8c714..b04f684f34 100644
--- a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
+++ b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
@@ -378,10 +378,7 @@ public class MediaPlayerList {
cb.run(playerId, false, "", 0);
return;
}
-
- mBrowsingPlayerId = playerId;
MediaBrowserWrapper wrapper = mMediaBrowserWrappers.get(playerId);
-
// If player is different than actual or if the given path is wrong, process rootId
if (playerId != mBrowsingPlayerId || currentPath.equals("")) {
wrapper.getRootId(
@@ -399,6 +396,7 @@ public class MediaPlayerList {
cb.run(playerId, true, currentPath, itemList.size());
});
}
+ mBrowsingPlayerId = playerId;
} else {
// Fix PTS AVRCP/TG/MCN/CB/BI-02-C
if (Utils.isPtsTestMode()) {
diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
index 93579a845c..b6aa7cf8b6 100644
--- a/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
+++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
@@ -66,7 +66,6 @@ public class AvrcpTargetService extends ProfileService {
// Cover Art Service (Storage + BIP Server)
private final AvrcpCoverArtService mAvrcpCoverArtService;
- private final AdapterService mAdapterService;
private final AvrcpVersion mAvrcpVersion;
private final MediaPlayerList mMediaPlayerList;
private final PlayerSettingsManager mPlayerSettingsManager;
@@ -100,12 +99,29 @@ public class AvrcpTargetService extends ProfileService {
private static AvrcpTargetService sInstance = null;
public AvrcpTargetService(AdapterService adapterService) {
+ this(
+ requireNonNull(adapterService),
+ adapterService.getSystemService(AudioManager.class),
+ AvrcpNativeInterface.getInstance(),
+ new AvrcpVolumeManager(
+ requireNonNull(adapterService),
+ adapterService.getSystemService(AudioManager.class),
+ AvrcpNativeInterface.getInstance()),
+ Looper.myLooper());
+ }
+
+ @VisibleForTesting
+ AvrcpTargetService(
+ AdapterService adapterService,
+ AudioManager audioManager,
+ AvrcpNativeInterface nativeInterface,
+ AvrcpVolumeManager volumeManager,
+ Looper looper) {
super(requireNonNull(adapterService));
- mAdapterService = adapterService;
- mAudioManager = requireNonNull(getSystemService(AudioManager.class));
- mNativeInterface = requireNonNull(AvrcpNativeInterface.getInstance());
+ mAudioManager = requireNonNull(audioManager);
+ mNativeInterface = requireNonNull(nativeInterface);
- mMediaPlayerList = new MediaPlayerList(Looper.myLooper(), this);
+ mMediaPlayerList = new MediaPlayerList(looper, this);
IntentFilter userFilter = new IntentFilter();
userFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -119,7 +135,7 @@ public class AvrcpTargetService extends ProfileService {
mNativeInterface.init(this);
mAvrcpVersion = AvrcpVersion.getCurrentSystemPropertiesValue();
- mVolumeManager = new AvrcpVolumeManager(mAdapterService, mAudioManager, mNativeInterface);
+ mVolumeManager = requireNonNull(volumeManager);
UserManager userManager = getApplicationContext().getSystemService(UserManager.class);
if (userManager.isUserUnlocked()) {
@@ -257,6 +273,7 @@ public class AvrcpTargetService extends ProfileService {
mPlayerSettingsManager.cleanup();
mMediaPlayerList.cleanup();
mNativeInterface.cleanup();
+ mVolumeManager.cleanup();
getApplicationContext().unregisterReceiver(mUserUnlockedReceiver);
}
diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java
index 36301c2f54..b11aeebe24 100644
--- a/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java
+++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java
@@ -421,6 +421,11 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
mDeviceMap.remove(device);
}
+ /** Cleans up and unregisters any registered callbacks. */
+ void cleanup() {
+ mAudioManager.unregisterAudioDeviceCallback(this);
+ }
+
public void dump(StringBuilder sb) {
sb.append("AvrcpVolumeManager:\n");
sb.append(" mCurrentDevice: ").append(mCurrentDevice).append("\n");
diff --git a/android/app/src/com/android/bluetooth/bas/BatteryStateMachine.java b/android/app/src/com/android/bluetooth/bas/BatteryStateMachine.java
index 3038c5ee19..67b2b4a005 100644
--- a/android/app/src/com/android/bluetooth/bas/BatteryStateMachine.java
+++ b/android/app/src/com/android/bluetooth/bas/BatteryStateMachine.java
@@ -118,7 +118,7 @@ public class BatteryStateMachine extends StateMachine {
}
synchronized boolean isConnected() {
- return getCurrentState() == mConnected;
+ return mLastConnectionState == BluetoothProfile.STATE_CONNECTED;
}
private static String messageWhatToString(int what) {
@@ -153,17 +153,7 @@ public class BatteryStateMachine extends StateMachine {
@BluetoothProfile.BtProfileState
int getConnectionState() {
- String currentState = getCurrentState().getName();
- return switch (currentState) {
- case "Disconnected" -> BluetoothProfile.STATE_DISCONNECTED;
- case "Connecting" -> BluetoothProfile.STATE_CONNECTING;
- case "Connected" -> BluetoothProfile.STATE_CONNECTED;
- case "Disconnecting" -> BluetoothProfile.STATE_DISCONNECTING;
- default -> {
- Log.e(TAG, "Bad currentState: " + currentState);
- yield BluetoothProfile.STATE_DISCONNECTED;
- }
- };
+ return mLastConnectionState;
}
void dispatchConnectionStateChanged(int toState) {
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 72648cbcfd..581951caa6 100644
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
@@ -19,6 +19,7 @@ package com.android.bluetooth.bass_client;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.Manifest.permission.BLUETOOTH_SCAN;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
import static com.android.bluetooth.flags.Flags.leaudioAllowedContextMask;
@@ -27,6 +28,7 @@ import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiGetLocalMetad
import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeripheralEntrustment;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper;
+import static com.android.bluetooth.flags.Flags.leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator;
import static com.android.bluetooth.flags.Flags.leaudioSortScansToSyncByFails;
import android.annotation.RequiresPermission;
@@ -99,6 +101,7 @@ import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/** Broadcast Assistant Scan Service */
@@ -167,8 +170,8 @@ public class BassClientService extends ProfileService {
private final Map<BluetoothDevice, List<Integer>> mGroupManagedSources =
new ConcurrentHashMap<>();
private final Map<BluetoothDevice, List<Integer>> mActiveSourceMap = new ConcurrentHashMap<>();
- private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap =
- new ConcurrentHashMap<>();
+ private final Map<BluetoothDevice, Map<Integer, BluetoothLeBroadcastMetadata>>
+ mBroadcastMetadataMap = new ConcurrentHashMap<>();
private final HashSet<BluetoothDevice> mPausedBroadcastSinks = new HashSet<>();
private final Map<BluetoothDevice, Pair<Integer, Integer>> mSinksWaitingForPast =
new HashMap<>();
@@ -285,7 +288,7 @@ public class BassClientService extends ProfileService {
break;
}
Handler handler = getOrCreateHandler(broadcastId);
- if (!handler.hasMessagesOrCallbacks()) {
+ if (!hasAnyMessagesOrCallbacks(handler)) {
mHandlers.remove(broadcastId);
}
}
@@ -308,7 +311,7 @@ public class BassClientService extends ProfileService {
}
Handler handler = getOrCreateHandler(broadcastId);
handler.removeMessages(msg);
- if (!handler.hasMessagesOrCallbacks()) {
+ if (!hasAnyMessagesOrCallbacks(handler)) {
mHandlers.remove(broadcastId);
}
}
@@ -326,7 +329,7 @@ public class BassClientService extends ProfileService {
Map.Entry<Integer, Handler> entry = iterator.next();
Handler handler = entry.getValue();
handler.removeMessages(msg);
- if (!handler.hasMessagesOrCallbacks()) {
+ if (!hasAnyMessagesOrCallbacks(handler)) {
iterator.remove();
}
}
@@ -339,6 +342,16 @@ public class BassClientService extends ProfileService {
Handler handler = getOrCreateHandler(broadcastId);
return handler.hasMessages(msg);
}
+
+ private boolean hasAnyMessagesOrCallbacks(Handler handler) {
+ if (android.os.Flags.mainlineVcnPlatformApi()) {
+ return handler.hasMessagesOrCallbacks();
+ } else {
+ return handler.hasMessages(MESSAGE_SYNC_LOST_TIMEOUT)
+ || handler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)
+ || handler.hasMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
+ }
+ }
}
public BassClientService(Context ctx) {
@@ -907,10 +920,16 @@ public class BassClientService extends ProfileService {
private void enqueueSourceGroupOp(BluetoothDevice sink, Integer msgId, Object obj) {
log("enqueueSourceGroupOp device: " + sink + ", msgId: " + msgId);
- if (!mPendingGroupOp.containsKey(sink)) {
- mPendingGroupOp.put(sink, new ArrayList());
- }
- mPendingGroupOp.get(sink).add(new Pair<Integer, Object>(msgId, obj));
+ mPendingGroupOp.compute(
+ sink,
+ (key, opsToModify) -> {
+ List<Pair<Integer, Object>> operations =
+ (opsToModify == null)
+ ? new ArrayList<>()
+ : new ArrayList<>(opsToModify);
+ operations.add(new Pair<>(msgId, obj));
+ return operations;
+ });
}
private boolean isSuccess(int status) {
@@ -957,67 +976,73 @@ public class BassClientService extends ProfileService {
+ ", reqMsg: "
+ reqMsg);
- List<Pair<Integer, Object>> operations = mPendingGroupOp.get(sink);
- if (operations == null) {
- return;
- }
+ AtomicBoolean shouldUpdateAssistantActive = new AtomicBoolean(false);
- switch (reqMsg) {
- case BassClientStateMachine.ADD_BCAST_SOURCE:
- if (obj == null) {
- return;
- }
- // Identify the operation by operation type and broadcastId
- if (isSuccess(reason)) {
- BluetoothLeBroadcastReceiveState sourceState =
- (BluetoothLeBroadcastReceiveState) obj;
- boolean removed =
- operations.removeIf(
- m ->
- (m.first.equals(
- BassClientStateMachine
- .ADD_BCAST_SOURCE))
- && (sourceState.getBroadcastId()
- == ((BluetoothLeBroadcastMetadata)
- m.second)
- .getBroadcastId()));
- if (removed) {
- setSourceGroupManaged(sink, sourceState.getSourceId(), true);
- }
- } else {
- BluetoothLeBroadcastMetadata metadata = (BluetoothLeBroadcastMetadata) obj;
- operations.removeIf(
- m ->
- (m.first.equals(BassClientStateMachine.ADD_BCAST_SOURCE))
- && (metadata.getBroadcastId()
- == ((BluetoothLeBroadcastMetadata) m.second)
- .getBroadcastId()));
-
- if (!isAnyPendingAddSourceOperation()
- && mIsAssistantActive
- && mPausedBroadcastSinks.isEmpty()) {
- LeAudioService leAudioService = mServiceFactory.getLeAudioService();
- mIsAssistantActive = false;
- mUnicastSourceStreamStatus = Optional.empty();
-
- if (leAudioService != null) {
- leAudioService.activeBroadcastAssistantNotification(false);
- }
+ mPendingGroupOp.computeIfPresent(
+ sink,
+ (key, opsToModify) -> {
+ List<Pair<Integer, Object>> operations = new ArrayList<>(opsToModify);
+
+ switch (reqMsg) {
+ case BassClientStateMachine.ADD_BCAST_SOURCE:
+ if (obj == null) {
+ return operations;
+ }
+ // Identify the operation by operation type and broadcastId
+ if (isSuccess(reason)) {
+ BluetoothLeBroadcastReceiveState sourceState =
+ (BluetoothLeBroadcastReceiveState) obj;
+ if (removeMatchingOperation(operations, reqMsg, obj)) {
+ setSourceGroupManaged(sink, sourceState.getSourceId(), true);
+ }
+ } else {
+ removeMatchingOperation(operations, reqMsg, obj);
+ shouldUpdateAssistantActive.set(true);
+ }
+ break;
+ case BassClientStateMachine.REMOVE_BCAST_SOURCE:
+ // Identify the operation by operation type and sourceId
+ removeMatchingOperation(operations, reqMsg, obj);
+ Integer sourceId = (Integer) obj;
+ setSourceGroupManaged(sink, sourceId, false);
+ break;
+ default:
+ break;
}
- }
- break;
- case BassClientStateMachine.REMOVE_BCAST_SOURCE:
- // Identify the operation by operation type and sourceId
- Integer sourceId = (Integer) obj;
- operations.removeIf(
- m ->
- m.first.equals(BassClientStateMachine.REMOVE_BCAST_SOURCE)
- && (sourceId.equals((Integer) m.second)));
- setSourceGroupManaged(sink, sourceId, false);
- break;
- default:
- break;
+ return operations;
+ });
+
+ if (shouldUpdateAssistantActive.get()
+ && !isAnyPendingAddSourceOperation()
+ && mIsAssistantActive
+ && mPausedBroadcastSinks.isEmpty()) {
+ LeAudioService leAudioService = mServiceFactory.getLeAudioService();
+ mIsAssistantActive = false;
+ mUnicastSourceStreamStatus = Optional.empty();
+
+ if (leAudioService != null) {
+ leAudioService.activeBroadcastAssistantNotification(false);
+ }
+ }
+ }
+
+ private boolean removeMatchingOperation(
+ List<Pair<Integer, Object>> operations, int reqMsg, Object obj) {
+ return operations.removeIf(
+ m -> m.first.equals(reqMsg) && isMatchingOperation(m.second, obj));
+ }
+
+ private boolean isMatchingOperation(Object operationData, Object obj) {
+ if (obj instanceof BluetoothLeBroadcastReceiveState) {
+ return ((BluetoothLeBroadcastMetadata) operationData).getBroadcastId()
+ == ((BluetoothLeBroadcastReceiveState) obj).getBroadcastId();
+ } else if (obj instanceof BluetoothLeBroadcastMetadata) {
+ return ((BluetoothLeBroadcastMetadata) operationData).getBroadcastId()
+ == ((BluetoothLeBroadcastMetadata) obj).getBroadcastId();
+ } else if (obj instanceof Integer) {
+ return obj.equals(operationData);
}
+ return false;
}
private boolean isDevicePartOfActiveUnicastGroup(BluetoothDevice device) {
@@ -1159,8 +1184,12 @@ public class BassClientService extends ProfileService {
return;
}
- boolean isAssistantActive =
- areReceiversReceivingOnlyExternalBroadcast(getConnectedDevices());
+ boolean isAssistantActive;
+ if (leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()) {
+ isAssistantActive = hasPrimaryDeviceManagedExternalBroadcast();
+ } else {
+ isAssistantActive = areReceiversReceivingOnlyExternalBroadcast(getConnectedDevices());
+ }
if (isAssistantActive) {
/* Assistant become active */
@@ -1325,10 +1354,15 @@ public class BassClientService extends ProfileService {
return false;
}
boolean isRoomAvailable = false;
- for (BluetoothLeBroadcastReceiveState recvState : stateMachine.getAllSources()) {
- if (isEmptyBluetoothDevice(recvState.getSourceDevice())) {
- isRoomAvailable = true;
- break;
+ List<BluetoothLeBroadcastReceiveState> sources = stateMachine.getAllSources();
+ if (sources.size() < stateMachine.getMaximumSourceCapacity()) {
+ isRoomAvailable = true;
+ } else {
+ for (BluetoothLeBroadcastReceiveState recvState : sources) {
+ if (isEmptyBluetoothDevice(recvState.getSourceDevice())) {
+ isRoomAvailable = true;
+ break;
+ }
}
}
log("isRoomAvailable: " + isRoomAvailable);
@@ -1514,7 +1548,7 @@ public class BassClientService extends ProfileService {
return BluetoothStatusCodes.ERROR_BAD_PARAMETERS;
}
- if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
+ if (getConnectionState(device) != STATE_CONNECTED) {
log("validateParameters: device is not connected, device: " + device);
return BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR;
}
@@ -1643,10 +1677,10 @@ public class BassClientService extends ProfileService {
}
/* Restore allowed context mask for unicast in case if last connected broadcast
- * delegator device which has external source disconnectes.
+ * delegator device which has external source disconnects.
*/
checkAndResetGroupAllowedContextMask();
- } else if (toState == BluetoothProfile.STATE_CONNECTED) {
+ } else if (toState == STATE_CONNECTED) {
handleReconnectingAudioSharingModeDevice(device);
}
}
@@ -2860,6 +2894,77 @@ public class BassClientService extends ProfileService {
}
}
+ private void storeSinkMetadata(
+ BluetoothDevice device, int broadcastId, BluetoothLeBroadcastMetadata metadata) {
+ if (device == null
+ || broadcastId == BassConstants.INVALID_BROADCAST_ID
+ || metadata == null) {
+ Log.e(
+ TAG,
+ "Failed to store Sink Metadata, invalid parameters (device: "
+ + device
+ + ", broadcastId: "
+ + broadcastId
+ + ", metadata: "
+ + metadata
+ + ")");
+ return;
+ }
+
+ mBroadcastMetadataMap.compute(
+ device,
+ (key, existingMap) -> {
+ if (existingMap == null) {
+ existingMap = new ConcurrentHashMap<>();
+ }
+ existingMap.put(broadcastId, metadata);
+ return existingMap;
+ });
+ }
+
+ private void removeSinkMetadata(BluetoothDevice device, int broadcastId) {
+ if (device == null || broadcastId == BassConstants.INVALID_BROADCAST_ID) {
+ Log.e(
+ TAG,
+ "Failed to remove Sink Metadata, invalid parameters (device: "
+ + device
+ + ", broadcastId: "
+ + broadcastId
+ + ")");
+ return;
+ }
+
+ mBroadcastMetadataMap.compute(
+ device,
+ (key, existingMap) -> {
+ if (existingMap != null) {
+ existingMap.remove(broadcastId);
+ if (existingMap.isEmpty()) {
+ return null;
+ }
+ } else {
+ Log.w(
+ TAG,
+ "There is no metadata related to sink (device: "
+ + device
+ + ", broadcastId: "
+ + broadcastId);
+ }
+ return existingMap;
+ });
+ }
+
+ private void removeSinkMetadata(BluetoothDevice device) {
+ if (device == null) {
+ Log.e(
+ TAG,
+ "Failed to remove Sink Metadata, invalid parameters (device: " + device + ")");
+ return;
+ }
+
+ mBroadcastMetadataMap.remove(device);
+ }
+
/**
* Add a Broadcast Source to the Broadcast Sink
*
@@ -3029,7 +3134,7 @@ public class BassClientService extends ProfileService {
}
/* Store metadata for sink device */
- mBroadcastMetadataMap.put(device, sourceMetadata);
+ storeSinkMetadata(device, sourceMetadata.getBroadcastId(), sourceMetadata);
Message message =
stateMachine.obtainMessage(BassClientStateMachine.SWITCH_BCAST_SOURCE);
@@ -3057,7 +3162,7 @@ public class BassClientService extends ProfileService {
}
/* Store metadata for sink device */
- mBroadcastMetadataMap.put(device, sourceMetadata);
+ storeSinkMetadata(device, sourceMetadata.getBroadcastId(), sourceMetadata);
if (isGroupOp) {
enqueueSourceGroupOp(
@@ -3121,7 +3226,7 @@ public class BassClientService extends ProfileService {
}
/* Update metadata for sink device */
- mBroadcastMetadataMap.put(sink, updatedMetadata);
+ storeSinkMetadata(sink, updatedMetadata.getBroadcastId(), updatedMetadata);
byte[] code = updatedMetadata.getBroadcastCode();
for (Map.Entry<BluetoothDevice, Integer> deviceSourceIdPair : devices.entrySet()) {
@@ -3190,16 +3295,13 @@ public class BassClientService extends ProfileService {
Map<BluetoothDevice, Integer> devices = getGroupManagedDeviceSources(sink, sourceId).second;
for (Map.Entry<BluetoothDevice, Integer> deviceSourceIdPair : devices.entrySet()) {
BluetoothDevice device = deviceSourceIdPair.getKey();
- /* Removes metadata for sink device if not paused */
- if (!mPausedBroadcastSinks.contains(device)) {
- mBroadcastMetadataMap.remove(device);
- }
Integer deviceSourceId = deviceSourceIdPair.getValue();
BassClientStateMachine stateMachine = getOrCreateStateMachine(device);
int statusCode =
validateParametersForSourceOperation(stateMachine, device, deviceSourceId);
if (statusCode != BluetoothStatusCodes.SUCCESS) {
+ removeSinkMetadata(device);
mCallbacks.notifySourceRemoveFailed(device, sourceId, statusCode);
continue;
}
@@ -3207,6 +3309,15 @@ public class BassClientService extends ProfileService {
BluetoothLeBroadcastMetadata metaData =
stateMachine.getCurrentBroadcastMetadata(sourceId);
+ /* Removes metadata for sink device if not paused */
+ if (!mPausedBroadcastSinks.contains(device)) {
+ if (metaData != null) {
+ removeSinkMetadata(device, metaData.getBroadcastId());
+ } else {
+ removeSinkMetadata(device);
+ }
+ }
+
if (metaData != null) {
stopBigMonitoring(metaData.getBroadcastId(), true);
}
@@ -3555,13 +3666,13 @@ public class BassClientService extends ProfileService {
continue;
}
- mBroadcastMetadataMap.remove(sink);
+ removeSinkMetadata(sink);
/* Check if there is any other primary device receiving this broadcast */
if (devices.stream()
.anyMatch(
d ->
- ((getConnectionState(d) == BluetoothProfile.STATE_CONNECTED)
+ ((getConnectionState(d) == STATE_CONNECTED)
&& leAudioService.isPrimaryDevice(d)))) {
continue;
}
@@ -3582,8 +3693,7 @@ public class BassClientService extends ProfileService {
d ->
!d.equals(sink)
&& (getConnectionState(d)
- == BluetoothProfile
- .STATE_CONNECTED))) {
+ == STATE_CONNECTED))) {
iterator.remove();
leAudioService.stopBroadcast(broadcastId);
continue;
@@ -3594,47 +3704,54 @@ public class BassClientService extends ProfileService {
.anyMatch(
d ->
!d.equals(sink)
- && (getConnectionState(d)
- == BluetoothProfile.STATE_CONNECTED))) {
+ && (getConnectionState(d) == STATE_CONNECTED))) {
continue;
- } else {
- Log.d(
- TAG,
- "handleUnintendedDeviceDisconnection: No more potential broadcast "
- + "(broadcast ID: "
- + broadcastId
- + ") receivers - stopping broadcast");
- mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(broadcastId);
- mHandler.postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS);
}
+ Log.d(
+ TAG,
+ "handleUnintendedDeviceDisconnection: No more potential broadcast "
+ + "(broadcast ID: "
+ + broadcastId
+ + ") receivers - stopping broadcast");
+ mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(broadcastId);
+ mHandler.postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS);
}
}
}
/** Handle device newly connected and its peer device still has active source */
private void checkAndResumeBroadcast(BluetoothDevice sink) {
- BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink);
- if (metadata == null) {
- Log.d(TAG, "checkAndResumeBroadcast: no metadata available");
+ Map<Integer, BluetoothLeBroadcastMetadata> entry = mBroadcastMetadataMap.get(sink);
+
+ if (entry == null) {
+ Log.d(TAG, "checkAndResumeBroadcast: no entry for device: " + sink + ", available");
return;
}
- for (BluetoothDevice groupDevice : getTargetDeviceList(sink, true)) {
- if (groupDevice.equals(sink)) {
+
+ for (Map.Entry<Integer, BluetoothLeBroadcastMetadata> idMetadataIdPair : entry.entrySet()) {
+ BluetoothLeBroadcastMetadata metadata = idMetadataIdPair.getValue();
+ if (metadata == null) {
+ Log.d(TAG, "checkAndResumeBroadcast: no metadata available");
continue;
}
- // Check peer device
- Optional<BluetoothLeBroadcastReceiveState> receiver =
- getOrCreateStateMachine(groupDevice).getAllSources().stream()
- .filter(e -> e.getBroadcastId() == metadata.getBroadcastId())
- .findAny();
- if (receiver.isPresent()
- && !getAllSources(sink).stream()
- .anyMatch(
- rs ->
- (rs.getBroadcastId()
- == receiver.get().getBroadcastId()))) {
- Log.d(TAG, "checkAndResumeBroadcast: restore the source for device: " + sink);
- addSource(sink, metadata, false);
+ for (BluetoothDevice groupDevice : getTargetDeviceList(sink, true)) {
+ if (groupDevice.equals(sink)) {
+ continue;
+ }
+ // Check peer device
+ Optional<BluetoothLeBroadcastReceiveState> receiver =
+ getOrCreateStateMachine(groupDevice).getAllSources().stream()
+ .filter(e -> e.getBroadcastId() == metadata.getBroadcastId())
+ .findAny();
+ if (receiver.isPresent()
+ && !getAllSources(sink).stream()
+ .anyMatch(
+ rs ->
+ (rs.getBroadcastId()
+ == receiver.get().getBroadcastId()))) {
+ Log.d(TAG, "checkAndResumeBroadcast: restore the source for device: " + sink);
+ addSource(sink, metadata, false);
+ }
}
}
}
@@ -3768,65 +3885,67 @@ public class BassClientService extends ProfileService {
while (iterator.hasNext()) {
BluetoothDevice sink = iterator.next();
sEventLogger.logd(TAG, "Remove broadcast sink from paused cache: " + sink);
- BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink);
+ Map<Integer, BluetoothLeBroadcastMetadata> entry =
+ mBroadcastMetadataMap.getOrDefault(sink, Collections.emptyMap());
- if (leaudioBroadcastAssistantPeripheralEntrustment()
- || leaudioBroadcastResyncHelper()) {
- if (metadata == null) {
- Log.w(
- TAG,
- "resumeReceiversSourceSynchronization: failed to get metadata to"
- + " resume sink: "
- + sink);
- // remove the device from mPausedBroadcastSinks
- iterator.remove();
- continue;
- }
+ for (BluetoothLeBroadcastMetadata metadata : entry.values()) {
- mPausedBroadcastIds.remove(metadata.getBroadcastId());
+ if (leaudioBroadcastAssistantPeripheralEntrustment()
+ || leaudioBroadcastResyncHelper()) {
+ if (metadata == null) {
+ Log.w(
+ TAG,
+ "resumeReceiversSourceSynchronization: failed to get metadata to"
+ + " resume sink: "
+ + sink);
+ continue;
+ }
- // For each device, find the source ID having this broadcast ID
- BassClientStateMachine stateMachine = getOrCreateStateMachine(sink);
- List<BluetoothLeBroadcastReceiveState> sources = stateMachine.getAllSources();
- Optional<BluetoothLeBroadcastReceiveState> receiveState =
- sources.stream()
- .filter(e -> e.getBroadcastId() == metadata.getBroadcastId())
- .findAny();
+ mPausedBroadcastIds.remove(metadata.getBroadcastId());
- if (leaudioBroadcastResyncHelper()
- && receiveState.isPresent()
- && (receiveState.get().getPaSyncState()
- == BluetoothLeBroadcastReceiveState
- .PA_SYNC_STATE_SYNCINFO_REQUEST
- || receiveState.get().getPaSyncState()
- == BluetoothLeBroadcastReceiveState
- .PA_SYNC_STATE_SYNCHRONIZED)) {
- iterator.remove();
- continue;
- }
+ // For each device, find the source ID having this broadcast ID
+ BassClientStateMachine stateMachine = getOrCreateStateMachine(sink);
+ List<BluetoothLeBroadcastReceiveState> sources = stateMachine.getAllSources();
+ Optional<BluetoothLeBroadcastReceiveState> receiveState =
+ sources.stream()
+ .filter(e -> e.getBroadcastId() == metadata.getBroadcastId())
+ .findAny();
- List<Integer> activeSyncedSrc = getActiveSyncedSources();
+ if (leaudioBroadcastResyncHelper()
+ && receiveState.isPresent()
+ && (receiveState.get().getPaSyncState()
+ == BluetoothLeBroadcastReceiveState
+ .PA_SYNC_STATE_SYNCINFO_REQUEST
+ || receiveState.get().getPaSyncState()
+ == BluetoothLeBroadcastReceiveState
+ .PA_SYNC_STATE_SYNCHRONIZED)) {
+ continue;
+ }
- if (receiveState.isPresent()
- && (!leaudioBroadcastResyncHelper()
- || isLocalBroadcast(metadata)
- || activeSyncedSrc.contains(
- getSyncHandleForBroadcastId(metadata.getBroadcastId())))) {
- int sourceId = receiveState.get().getSourceId();
- updateSourceToResumeBroadcast(sink, sourceId, metadata);
- } else {
- addSource(sink, metadata, false);
- }
- } else {
- if (metadata != null) {
- mPausedBroadcastIds.remove(metadata.getBroadcastId());
- addSource(sink, metadata, false);
+ List<Integer> activeSyncedSrc = getActiveSyncedSources();
+
+ if (receiveState.isPresent()
+ && (!leaudioBroadcastResyncHelper()
+ || isLocalBroadcast(metadata)
+ || activeSyncedSrc.contains(
+ getSyncHandleForBroadcastId(
+ metadata.getBroadcastId())))) {
+ int sourceId = receiveState.get().getSourceId();
+ updateSourceToResumeBroadcast(sink, sourceId, metadata);
+ } else {
+ addSource(sink, metadata, false);
+ }
} else {
- Log.w(
- TAG,
- "resumeReceiversSourceSynchronization: failed to get metadata to"
- + " resume sink: "
- + sink);
+ if (metadata != null) {
+ mPausedBroadcastIds.remove(metadata.getBroadcastId());
+ addSource(sink, metadata, false);
+ } else {
+ Log.w(
+ TAG,
+ "resumeReceiversSourceSynchronization: failed to get metadata to"
+ + " resume sink: "
+ + sink);
+ }
}
}
// remove the device from mPausedBroadcastSinks
@@ -3928,10 +4047,7 @@ public class BassClientService extends ProfileService {
for (BluetoothDevice device : devices) {
for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) {
for (int i = 0; i < receiveState.getNumSubgroups(); i++) {
- Long syncState = receiveState.getBisSyncState().get(i);
- /* Synced to BIS */
- if (syncState != BassConstants.BIS_SYNC_NOT_SYNC_TO_BIS
- && syncState != BassConstants.BIS_SYNC_FAILED_SYNC_TO_BIG) {
+ if (isSyncedToBroadcastStream(receiveState.getBisSyncState().get(i))) {
return true;
}
}
@@ -3941,6 +4057,35 @@ public class BassClientService extends ProfileService {
return false;
}
+ public boolean hasPrimaryDeviceManagedExternalBroadcast() {
+ LeAudioService leAudioService = mServiceFactory.getLeAudioService();
+
+ if (leAudioService == null) {
+ Log.e(TAG, "no LeAudioService");
+ return false;
+ }
+
+ for (BluetoothDevice device : getConnectedDevices()) {
+ if (!leAudioService.isPrimaryDevice(device)) {
+ continue;
+ }
+
+ Map<Integer, BluetoothLeBroadcastMetadata> entry = mBroadcastMetadataMap.get(device);
+
+ /* null means that this source was not added or modified by assistant */
+ if (entry == null) {
+ continue;
+ }
+
+ /* Assistant manages some external broadcast */
+ if (entry.values().stream().anyMatch(e -> !isLocalBroadcast(e))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/** Check if any sink receivers are receiving broadcast stream */
public boolean areReceiversReceivingOnlyExternalBroadcast(List<BluetoothDevice> devices) {
boolean isReceivingExternalBroadcast = false;
@@ -3948,10 +4093,7 @@ public class BassClientService extends ProfileService {
for (BluetoothDevice device : devices) {
for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) {
for (int i = 0; i < receiveState.getNumSubgroups(); i++) {
- Long syncState = receiveState.getBisSyncState().get(i);
- /* Synced to BIS */
- if (syncState != BassConstants.BIS_SYNC_NOT_SYNC_TO_BIS
- && syncState != BassConstants.BIS_SYNC_FAILED_SYNC_TO_BIG) {
+ if (isSyncedToBroadcastStream(receiveState.getBisSyncState().get(i))) {
if (isLocalBroadcast(receiveState)) {
return false;
} else {
@@ -3981,10 +4123,7 @@ public class BassClientService extends ProfileService {
return true;
} else {
for (int i = 0; i < receiveState.getNumSubgroups(); i++) {
- Long syncState = receiveState.getBisSyncState().get(i);
- /* Synced to BIS */
- if (syncState != BassConstants.BIS_SYNC_NOT_SYNC_TO_BIS
- && syncState != BassConstants.BIS_SYNC_FAILED_SYNC_TO_BIG) {
+ if (isSyncedToBroadcastStream(receiveState.getBisSyncState().get(i))) {
return true;
}
}
@@ -4034,14 +4173,7 @@ public class BassClientService extends ProfileService {
.anyMatch(
receiveState ->
(receiveState.getBisSyncState().stream()
- .anyMatch(
- syncState ->
- syncState
- != BassConstants
- .BIS_SYNC_NOT_SYNC_TO_BIS
- && syncState
- != BassConstants
- .BIS_SYNC_FAILED_SYNC_TO_BIG)))) {
+ .anyMatch(this::isSyncedToBroadcastStream)))) {
activeSinks.add(device);
}
}
@@ -4049,6 +4181,11 @@ public class BassClientService extends ProfileService {
return activeSinks;
}
+ private boolean isSyncedToBroadcastStream(Long syncState) {
+ return syncState != BassConstants.BIS_SYNC_NOT_SYNC_TO_BIS
+ && syncState != BassConstants.BIS_SYNC_FAILED_SYNC_TO_BIG;
+ }
+
/** Handle broadcast state changed */
public void notifyBroadcastStateChanged(int state, int broadcastId) {
switch (state) {
@@ -4178,7 +4315,7 @@ public class BassClientService extends ProfileService {
try {
invokeCallback(callback, msg);
} catch (RemoteException e) {
- continue;
+ // Ignore exception
}
}
mCallbacksList.finishBroadcast();
diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
index 5954b827b0..efdc0dcae7 100644
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState;
+import static com.android.bluetooth.flags.Flags.leaudioBroadcastReceiveStateProcessingRefactor;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper;
import android.annotation.Nullable;
@@ -155,6 +156,7 @@ class BassClientStateMachine extends StateMachine {
private final Map<Integer, Boolean> mFirstTimeBisDiscoveryMap;
private int mPASyncRetryCounter = 0;
@VisibleForTesting int mNumOfBroadcastReceiverStates = 0;
+ int mNumOfReadyBroadcastReceiverStates = 0;
@VisibleForTesting int mPendingOperation = -1;
@VisibleForTesting byte mPendingSourceId = -1;
@VisibleForTesting BluetoothLeBroadcastMetadata mPendingMetadata = null;
@@ -975,10 +977,15 @@ class BassClientStateMachine extends StateMachine {
}
private boolean isSourceAbsent(BluetoothLeBroadcastReceiveState recvState) {
- return recvState.getSourceDevice() == null
+ return recvState == null
+ || recvState.getSourceDevice() == null
|| recvState.getSourceDevice().getAddress().equals("00:00:00:00:00:00");
}
+ private boolean isSourcePresent(BluetoothLeBroadcastReceiveState recvState) {
+ return !isSourceAbsent(recvState);
+ }
+
private void checkAndUpdateBroadcastCode(BluetoothLeBroadcastReceiveState recvState) {
log("checkAndUpdateBroadcastCode");
// Whenever receive state indicated code requested, assistant should set the broadcast code
@@ -999,7 +1006,8 @@ class BassClientStateMachine extends StateMachine {
}
}
- private BluetoothLeBroadcastReceiveState parseBroadcastReceiverState(byte[] receiverState) {
+ private BluetoothLeBroadcastReceiveState parseBroadcastReceiverStateObsolete(
+ byte[] receiverState) {
byte sourceId = 0;
if (receiverState.length > 0) {
sourceId = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX];
@@ -1140,10 +1148,11 @@ class BassClientStateMachine extends StateMachine {
return recvState;
}
- private void processBroadcastReceiverState(
+ private void processBroadcastReceiverStateObsolete(
byte[] receiverState, BluetoothGattCharacteristic characteristic) {
log("processBroadcastReceiverState: characteristic:" + characteristic);
- BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverState(receiverState);
+ BluetoothLeBroadcastReceiveState recvState =
+ parseBroadcastReceiverStateObsolete(receiverState);
if (recvState == null) {
log("processBroadcastReceiverState: Null recvState");
return;
@@ -1249,6 +1258,226 @@ class BassClientStateMachine extends StateMachine {
broadcastReceiverState(recvState, sourceId);
}
+ private BluetoothLeBroadcastReceiveState parseBroadcastReceiverState(
+ byte[] receiverState, int previousSourceId) {
+ log("parseBroadcastReceiverState: receiverState length: " + receiverState.length);
+
+ BluetoothLeBroadcastReceiveState recvState = null;
+ if (receiverState.length == 0) {
+ byte[] emptyBluetoothDeviceAddress = Utils.getBytesFromAddress("00:00:00:00:00:00");
+ if (previousSourceId != BassConstants.INVALID_SOURCE_ID) {
+ recvState =
+ new BluetoothLeBroadcastReceiveState(
+ previousSourceId,
+ BluetoothDevice.ADDRESS_TYPE_PUBLIC, // sourceAddressType
+ mAdapterService.getDeviceFromByte(
+ emptyBluetoothDeviceAddress), // sourceDev
+ 0, // sourceAdvertisingSid
+ 0, // broadcastId
+ BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, // paSyncState
+ // bigEncryptionState
+ BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED,
+ null, // badCode
+ 0, // numSubgroups
+ Arrays.asList(new Long[0]), // bisSyncState
+ Arrays.asList(
+ new BluetoothLeAudioContentMetadata[0]) // subgroupMetadata
+ );
+ } else {
+ log("parseBroadcastReceiverState: unknown sourceId");
+ }
+ } else {
+ byte sourceId = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX];
+ byte paSyncState = receiverState[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX];
+ byte bigEncryptionStatus = receiverState[BassConstants.BCAST_RCVR_STATE_ENC_STATUS_IDX];
+ byte[] badBroadcastCode = null;
+ int badBroadcastCodeLen = 0;
+ if (bigEncryptionStatus
+ == BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE) {
+ badBroadcastCode = new byte[BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE];
+ System.arraycopy(
+ receiverState,
+ BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX,
+ badBroadcastCode,
+ 0,
+ BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE);
+ badBroadcastCodeLen = BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE;
+ }
+ byte numSubGroups =
+ receiverState[
+ BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX + badBroadcastCodeLen];
+ int offset = BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX + badBroadcastCodeLen + 1;
+ ArrayList<BluetoothLeAudioContentMetadata> metadataList =
+ new ArrayList<BluetoothLeAudioContentMetadata>();
+ ArrayList<Long> bisSyncState = new ArrayList<Long>();
+ for (int i = 0; i < numSubGroups; i++) {
+ byte[] bisSyncIndex = new byte[Long.BYTES];
+ System.arraycopy(
+ receiverState,
+ offset,
+ bisSyncIndex,
+ 0,
+ BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE);
+ offset += BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE;
+ bisSyncState.add((long) Utils.byteArrayToLong(bisSyncIndex));
+
+ int metaDataLength = receiverState[offset++] & 0xFF;
+ if (metaDataLength > 0) {
+ log("metadata of length: " + metaDataLength + "is available");
+ byte[] metaData = new byte[metaDataLength];
+ System.arraycopy(receiverState, offset, metaData, 0, metaDataLength);
+ offset += metaDataLength;
+ metadataList.add(BluetoothLeAudioContentMetadata.fromRawBytes(metaData));
+ } else {
+ metadataList.add(BluetoothLeAudioContentMetadata.fromRawBytes(new byte[0]));
+ }
+ }
+ byte[] broadcastIdBytes = new byte[mBroadcastSourceIdLength];
+ System.arraycopy(
+ receiverState,
+ BassConstants.BCAST_RCVR_STATE_SRC_BCAST_ID_START_IDX,
+ broadcastIdBytes,
+ 0,
+ mBroadcastSourceIdLength);
+ int broadcastId = BassUtils.parseBroadcastId(broadcastIdBytes);
+ byte[] sourceAddress = new byte[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_SIZE];
+ System.arraycopy(
+ receiverState,
+ BassConstants.BCAST_RCVR_STATE_SRC_ADDR_START_IDX,
+ sourceAddress,
+ 0,
+ BassConstants.BCAST_RCVR_STATE_SRC_ADDR_SIZE);
+ byte sourceAddressType =
+ receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_TYPE_IDX];
+ BassUtils.reverse(sourceAddress);
+ String address = Utils.getAddressStringFromByte(sourceAddress);
+ BluetoothDevice device =
+ BluetoothAdapter.getDefaultAdapter()
+ .getRemoteLeDevice(address, sourceAddressType);
+ byte sourceAdvSid = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ADV_SID_IDX];
+ recvState =
+ new BluetoothLeBroadcastReceiveState(
+ sourceId,
+ (int) sourceAddressType,
+ device,
+ sourceAdvSid,
+ broadcastId,
+ (int) paSyncState,
+ (int) bigEncryptionStatus,
+ badBroadcastCode,
+ numSubGroups,
+ bisSyncState,
+ metadataList);
+ }
+ return recvState;
+ }
+
+ private void processBroadcastReceiverState(
+ byte[] receiverState, BluetoothGattCharacteristic characteristic) {
+ log(
+ "processBroadcastReceiverState: characteristic:"
+ + characteristic
+ + ", instanceId:"
+ + characteristic.getInstanceId());
+
+ BluetoothLeBroadcastReceiveState prevRecvState =
+ mBluetoothLeBroadcastReceiveStates.get(characteristic.getInstanceId());
+ if (prevRecvState == null
+ && (mBluetoothLeBroadcastReceiveStates.size() == mNumOfBroadcastReceiverStates)) {
+ Log.e(TAG, "processBroadcastReceiverState: reached the Max SourceInfos");
+ return;
+ }
+
+ int prevSourceId = BassConstants.INVALID_SOURCE_ID;
+ if (prevRecvState != null) {
+ prevSourceId = prevRecvState.getSourceId();
+ }
+
+ BluetoothLeBroadcastReceiveState recvState =
+ parseBroadcastReceiverState(receiverState, prevSourceId);
+ if (recvState == null) {
+ log("processBroadcastReceiverState: Null recvState");
+ return;
+ }
+
+ log("processBroadcastReceiverState: Updated receiver state: " + recvState);
+ mBluetoothLeBroadcastReceiveStates.put(characteristic.getInstanceId(), recvState);
+ int sourceId = recvState.getSourceId();
+
+ if (isSourceAbsent(prevRecvState) && isSourcePresent(recvState)) {
+ log("processBroadcastReceiverState: Source Addition");
+ removeMessages(CANCEL_PENDING_SOURCE_OPERATION);
+ if (mPendingMetadata != null) {
+ setCurrentBroadcastMetadata(sourceId, mPendingMetadata);
+ mPendingMetadata = null;
+ }
+ if (mPendingOperation == ADD_BCAST_SOURCE) {
+ mService.getCallbacks()
+ .notifySourceAdded(
+ mDevice, recvState, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
+ } else {
+ mService.getCallbacks()
+ .notifySourceAdded(
+ mDevice, recvState, BluetoothStatusCodes.REASON_REMOTE_REQUEST);
+ }
+ checkAndUpdateBroadcastCode(recvState);
+ processPASyncState(recvState);
+ processSyncStateChangeStats(recvState);
+ } else if (isSourcePresent(prevRecvState) && isSourcePresent(recvState)) {
+ log("processBroadcastReceiverState: Source Update");
+ removeMessages(CANCEL_PENDING_SOURCE_OPERATION);
+ if (mPendingMetadata != null) {
+ setCurrentBroadcastMetadata(sourceId, mPendingMetadata);
+ mPendingMetadata = null;
+ }
+ mService.getCallbacks()
+ .notifySourceModified(
+ mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
+ checkAndUpdateBroadcastCode(recvState);
+ processPASyncState(recvState);
+ processSyncStateChangeStats(recvState);
+
+ if (isPendingRemove(sourceId) && !isSyncedToTheSource(sourceId)) {
+ Message message = obtainMessage(REMOVE_BCAST_SOURCE);
+ message.arg1 = sourceId;
+ sendMessage(message);
+ }
+ } else if (isSourcePresent(prevRecvState) && isSourceAbsent(recvState)) {
+ BluetoothDevice removedDevice = prevRecvState.getSourceDevice();
+ log("processBroadcastReceiverState: Source Removal " + removedDevice);
+ if (!Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine()) {
+ cancelActiveSync(mService.getSyncHandleForBroadcastId(recvState.getBroadcastId()));
+ }
+ BluetoothLeBroadcastMetadata metaData = getCurrentBroadcastMetadata(sourceId);
+ if (metaData != null) {
+ logBroadcastSyncStatsWithStatus(
+ metaData.getBroadcastId(),
+ BluetoothStatsLog
+ .BROADCAST_AUDIO_SYNC_REPORTED__SYNC_STATUS__SYNC_STATUS_UNKNOWN);
+ }
+ setCurrentBroadcastMetadata(sourceId, null);
+ if (mPendingSourceToSwitch != null) {
+ // Source remove is triggered by switch source request
+ mService.getCallbacks()
+ .notifySourceRemoved(
+ mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST);
+ log("processBroadcastReceiverState: Source Switching");
+ Message message = obtainMessage(ADD_BCAST_SOURCE);
+ message.obj = mPendingSourceToSwitch;
+ sendMessage(message);
+ } else if (mPendingOperation == REMOVE_BCAST_SOURCE) {
+ mService.getCallbacks()
+ .notifySourceRemoved(
+ mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
+ } else {
+ mService.getCallbacks()
+ .notifySourceRemoved(
+ mDevice, sourceId, BluetoothStatusCodes.REASON_REMOTE_REQUEST);
+ }
+ }
+ broadcastReceiverState(recvState, sourceId);
+ }
+
// Implements callback methods for GATT events that the app cares about.
// For example, connection change and services discovered.
final class GattCallback extends BluetoothGattCallback {
@@ -1325,7 +1554,17 @@ class BassClientStateMachine extends StateMachine {
characteristic.getValue(),
0,
characteristic.getValue().length);
- processBroadcastReceiverState(characteristic.getValue(), characteristic);
+ if (leaudioBroadcastReceiveStateProcessingRefactor()) {
+ processBroadcastReceiverState(characteristic.getValue(), characteristic);
+ mNumOfReadyBroadcastReceiverStates++;
+ if (mNumOfReadyBroadcastReceiverStates == mNumOfBroadcastReceiverStates) {
+ // Notify service BASS state ready for operations
+ mService.getCallbacks().notifyBassStateReady(mDevice);
+ }
+ } else {
+ processBroadcastReceiverStateObsolete(
+ characteristic.getValue(), characteristic);
+ }
}
// switch to receiving notifications after initial characteristic read
BluetoothGattDescriptor desc =
@@ -1376,7 +1615,12 @@ class BassClientStateMachine extends StateMachine {
Log.e(TAG, "Remote receiver state is NULL");
return;
}
- processBroadcastReceiverState(characteristic.getValue(), characteristic);
+ if (leaudioBroadcastReceiveStateProcessingRefactor()) {
+ processBroadcastReceiverState(characteristic.getValue(), characteristic);
+ } else {
+ processBroadcastReceiverStateObsolete(
+ characteristic.getValue(), characteristic);
+ }
}
}
@@ -1625,6 +1869,7 @@ class BassClientStateMachine extends StateMachine {
mBroadcastScanControlPoint = null;
}
mNumOfBroadcastReceiverStates = 0;
+ mNumOfReadyBroadcastReceiverStates = 0;
if (mBluetoothLeBroadcastReceiveStates != null) {
mBluetoothLeBroadcastReceiveStates.clear();
}
diff --git a/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java b/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java
index f1f0b51691..981b2db0c7 100644
--- a/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java
+++ b/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java
@@ -49,6 +49,7 @@ public final class AbstractionLayer {
static final int BT_PROPERTY_REMOTE_ASHA_CAPABILITY = 0X15;
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;
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/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
index 6c79ab4789..6fb1169a9e 100644
--- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
@@ -412,7 +412,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
final LeAudioService leAudioService = mFactory.getLeAudioService();
setA2dpActiveDevice(null, true);
setHfpActiveDevice(null);
- if (Flags.admVerifyActiveFallbackDevice()) {
+ if (Flags.admVerifyActiveFallbackDevice() && leAudioService != null) {
setLeAudioActiveDevice(
null, !leAudioService.getActiveDevices().contains(device));
} else {
@@ -709,7 +709,6 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
+ device
+ ", mHfpActiveDevice="
+ mHfpActiveDevice);
-
if (!Objects.equals(mHfpActiveDevice, device)) {
if (device != null) {
setHearingAidActiveDevice(null, true);
@@ -717,10 +716,10 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
updateLeAudioActiveDeviceIfDualMode(mHfpActiveDevice, device);
- if (!Utils.isDualModeAudioEnabled() || device == null) {
+ if ((!Utils.isDualModeAudioEnabled() && device == null)) {
Log.d(TAG, "HFP active device is null. Try to fallback to the active device.");
synchronized (mLock) {
- setFallbackDeviceActiveLocked(null);
+ setFallbackDeviceActiveLocked(mHfpActiveDevice /* recentlyRemovedDevice */);
}
}
}
@@ -832,7 +831,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
if (device == null && !Utils.isDualModeAudioEnabled() && !isBroadcastingAudio()) {
Log.d(TAG, "LE audio active device is null. Try to fallback to the active device.");
synchronized (mLock) {
- setFallbackDeviceActiveLocked(device);
+ setFallbackDeviceActiveLocked(mLeAudioActiveDevice /* recentlyRemovedDevice */);
}
}
@@ -1136,12 +1135,18 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
Log.d(TAG, "setFallbackDeviceActive, recently removed: " + recentlyRemovedDevice);
mDbManager = mAdapterService.getDatabase();
List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
+ final LeAudioService leAudioService = mFactory.getLeAudioService();
if (!mHearingAidConnectedDevices.isEmpty()) {
connectedHearingAidDevices.addAll(mHearingAidConnectedDevices);
}
- if (!mLeHearingAidConnectedDevices.isEmpty()) {
- connectedHearingAidDevices.addAll(mLeHearingAidConnectedDevices);
+ if (!mLeHearingAidConnectedDevices.isEmpty() && leAudioService != null) {
+ for (BluetoothDevice dev : mLeHearingAidConnectedDevices) {
+ if (leAudioService.isGroupAvailableForStream(leAudioService.getGroupId(dev))) {
+ connectedHearingAidDevices.add(dev);
+ }
+ }
}
+
if (!connectedHearingAidDevices.isEmpty()) {
BluetoothDevice device =
mDbManager.getMostRecentlyConnectedDevicesInList(connectedHearingAidDevices);
@@ -1197,7 +1202,13 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
}
List<BluetoothDevice> connectedDevices = new ArrayList<>();
- connectedDevices.addAll(mLeAudioConnectedDevices);
+ if (leAudioService != null) {
+ for (BluetoothDevice dev : mLeAudioConnectedDevices) {
+ if (leAudioService.isGroupAvailableForStream(leAudioService.getGroupId(dev))) {
+ connectedDevices.add(dev);
+ }
+ }
+ }
Log.d(TAG, "Audio mode: " + mAudioManager.getMode());
switch (mAudioManager.getMode()) {
case AudioManager.MODE_NORMAL:
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java b/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java
index 33bf3c3f8f..64b5a0dfae 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java
@@ -195,13 +195,56 @@ public class AdapterNativeInterface {
return getMetricIdNative(address);
}
- int connectSocket(byte[] address, int type, byte[] uuid, int port, int flag, int callingUid) {
- return connectSocketNative(address, type, uuid, port, flag, callingUid);
+ int connectSocket(
+ byte[] address,
+ int type,
+ byte[] uuid,
+ int port,
+ int flag,
+ int callingUid,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize) {
+ return connectSocketNative(
+ address,
+ type,
+ uuid,
+ port,
+ flag,
+ callingUid,
+ dataPath,
+ socketName,
+ hubId,
+ endpointId,
+ maximumPacketSize);
}
int createSocketChannel(
- int type, String serviceName, byte[] uuid, int port, int flag, int callingUid) {
- return createSocketChannelNative(type, serviceName, uuid, port, flag, callingUid);
+ int type,
+ String serviceName,
+ byte[] uuid,
+ int port,
+ int flag,
+ int callingUid,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize) {
+ return createSocketChannelNative(
+ type,
+ serviceName,
+ uuid,
+ port,
+ flag,
+ callingUid,
+ dataPath,
+ socketName,
+ hubId,
+ endpointId,
+ maximumPacketSize);
}
void requestMaximumTxDataLength(byte[] address) {
@@ -359,10 +402,30 @@ public class AdapterNativeInterface {
private native int getMetricIdNative(byte[] address);
private native int connectSocketNative(
- byte[] address, int type, byte[] uuid, int port, int flag, int callingUid);
+ byte[] address,
+ int type,
+ byte[] uuid,
+ int port,
+ int flag,
+ int callingUid,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize);
private native int createSocketChannelNative(
- int type, String serviceName, byte[] uuid, int port, int flag, int callingUid);
+ int type,
+ String serviceName,
+ byte[] uuid,
+ int port,
+ int flag,
+ int callingUid,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize);
private native void requestMaximumTxDataLengthNative(byte[] address);
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java
index 851df2c030..b99debdede 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -134,6 +134,9 @@ class AdapterProperties {
private boolean mIsLeIsochronousBroadcasterSupported;
private boolean mIsLeChannelSoundingSupported;
+ private int mNumberOfSupportedOffloadedLeCocSockets;
+ private int mNumberOfSupportedOffloadedRfcommSockets;
+
// Lock for all getters and setters.
// If finer grained locking is needer, more locks
// can be added here.
@@ -908,6 +911,10 @@ class AdapterProperties {
updateDynamicAudioBufferSupport(val);
break;
+ case AbstractionLayer.BT_PROPERTY_LPP_OFFLOAD_FEATURES:
+ updateLppOffloadFeatureSupport(val);
+ break;
+
default:
Log.e(TAG, "Property change not handled in Java land:" + type);
}
@@ -1022,6 +1029,37 @@ class AdapterProperties {
mBufferConstraintList.complete(bufferConstraintList);
}
+ /**
+ * @return the mNumberOfSupportedOffloadedLeCocSockets
+ */
+ int getNumberOfSupportedOffloadedLeCocSockets() {
+ return mNumberOfSupportedOffloadedLeCocSockets;
+ }
+
+ /**
+ * @return the mNumberOfSupportedOffloadedRfcommSockets
+ */
+ int getNumberOfSupportedOffloadedRfcommSockets() {
+ return mNumberOfSupportedOffloadedRfcommSockets;
+ }
+
+ private void updateLppOffloadFeatureSupport(byte[] val) {
+ if (val == null || val.length < 2) {
+ Log.e(TAG, "BT_PROPERTY_LPP_OFFLOAD_FEATURES: invalid value length");
+ return;
+ }
+ mNumberOfSupportedOffloadedLeCocSockets = (0xFF & ((int) val[0]));
+ mNumberOfSupportedOffloadedRfcommSockets = (0xFF & ((int) val[1]));
+
+ Log.d(
+ TAG,
+ "BT_PROPERTY_LPP_OFFLOAD_FEATURES: update from Offload HAL"
+ + " mNumberOfSupportedOffloadedLeCocSockets = "
+ + mNumberOfSupportedOffloadedLeCocSockets
+ + " mNumberOfSupportedOffloadedRfcommSockets = "
+ + mNumberOfSupportedOffloadedRfcommSockets);
+ }
+
void onBluetoothReady() {
debugLog(
"onBluetoothReady, state="
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index 77b2c4cf28..798f9e3a9d 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -38,6 +38,7 @@ import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser;
import static com.android.bluetooth.Utils.getBytesFromAddress;
import static com.android.bluetooth.Utils.isDualModeAudioEnabled;
import static com.android.bluetooth.Utils.isPackageNameAccurate;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastV;
import static java.util.Objects.requireNonNull;
@@ -56,6 +57,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.ActiveDeviceProfile;
import android.bluetooth.BluetoothAdapter.ActiveDeviceUse;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevice.BluetoothAddress;
import android.bluetooth.BluetoothFrameworkInitializer;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothProfile;
@@ -89,7 +91,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.hardware.display.DisplayManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.os.AsyncTask;
import android.os.BatteryStatsManager;
import android.os.Binder;
@@ -277,10 +279,6 @@ public class AdapterService extends Service {
private final BluetoothHciVendorSpecificDispatcher mBluetoothHciVendorSpecificDispatcher =
new BluetoothHciVendorSpecificDispatcher();
- private final BluetoothHciVendorSpecificNativeInterface
- mBluetoothHciVendorSpecificNativeInterface =
- new BluetoothHciVendorSpecificNativeInterface(
- mBluetoothHciVendorSpecificDispatcher);
private final Looper mLooper;
private final AdapterServiceHandler mHandler;
@@ -345,6 +343,7 @@ public class AdapterService extends Service {
private BassClientService mBassClientService;
private BatteryService mBatteryService;
private BluetoothQualityReportNativeInterface mBluetoothQualityReportNativeInterface;
+ private BluetoothHciVendorSpecificNativeInterface mBluetoothHciVendorSpecificNativeInterface;
private GattService mGattService;
private ScanController mScanController;
@@ -695,7 +694,11 @@ public class AdapterService extends Service {
mBluetoothQualityReportNativeInterface.init();
if (Flags.hciVendorSpecificExtension()) {
- mBluetoothHciVendorSpecificNativeInterface.init();
+ mBluetoothHciVendorSpecificNativeInterface =
+ requireNonNull(
+ mBluetoothHciVendorSpecificNativeInterface.getInstance(),
+ "mBluetoothHciVendorSpecificNativeInterface cannot be null");
+ mBluetoothHciVendorSpecificNativeInterface.init(mBluetoothHciVendorSpecificDispatcher);
}
mSdpManager = new SdpManager(this, mLooper);
@@ -729,10 +732,10 @@ public class AdapterService extends Service {
mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);
- if (Flags.adapterSuspendMgmt()) {
+ if (Flags.adapterSuspendMgmt() && isAtLeastV()) {
mAdapterSuspend =
new AdapterSuspend(
- mNativeInterface, mLooper, getSystemService(DisplayManager.class));
+ mNativeInterface, mLooper, getSystemService(DeviceStateManager.class));
}
invalidateBluetoothCaches();
@@ -1478,7 +1481,9 @@ public class AdapterService extends Service {
}
if (mAdapterSuspend != null) {
- mAdapterSuspend.cleanup();
+ if (Flags.adapterSuspendMgmt() && isAtLeastV()) {
+ mAdapterSuspend.cleanup();
+ }
mAdapterSuspend = null;
}
@@ -2388,6 +2393,23 @@ public class AdapterService extends Service {
}
@Override
+ @NonNull
+ public BluetoothAddress getIdentityAddressWithType(@NonNull String address) {
+ AdapterService service = getService();
+ if (service == null
+ || !callerIsSystemOrActiveOrManagedUser(
+ service, TAG, "getIdentityAddressWithType")
+ || !Utils.checkConnectPermissionForDataDelivery(
+ service,
+ Utils.getCallingAttributionSource(mService),
+ "AdapterService getIdentityAddressWithType")) {
+ return new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN);
+ }
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ return service.getIdentityAddressWithType(address);
+ }
+
+ @Override
public String getName(AttributionSource source) {
AdapterService service = getService();
if (service == null
@@ -4369,6 +4391,26 @@ public class AdapterService extends Service {
service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
return service.mDatabaseManager.isMicrophonePreferredForCalls(device);
}
+
+ @Override
+ public boolean isLeCocSocketOffloadSupported(AttributionSource source) {
+ AdapterService service = getService();
+ if (service == null) {
+ return false;
+ }
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ return service.isLeCocSocketOffloadSupported();
+ }
+
+ @Override
+ public boolean isRfcommSocketOffloadSupported(AttributionSource source) {
+ AdapterService service = getService();
+ if (service == null) {
+ return false;
+ }
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ return service.isRfcommSocketOffloadSupported();
+ }
}
/**
@@ -4895,6 +4937,38 @@ public class AdapterService extends Service {
}
}
+ /**
+ * Returns the identity address and identity address type.
+ *
+ * @param address of remote device
+ * @return a {@link BluetoothDevice.BluetoothAddress} containing identity address and identity
+ * address type
+ */
+ @NonNull
+ public BluetoothAddress getIdentityAddressWithType(@NonNull String address) {
+ BluetoothDevice device =
+ BluetoothAdapter.getDefaultAdapter().getRemoteDevice(Ascii.toUpperCase(address));
+ DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
+
+ String identityAddress = null;
+ int identityAddressType = BluetoothDevice.ADDRESS_TYPE_UNKNOWN;
+
+ if (deviceProp != null) {
+ if (deviceProp.getIdentityAddress() != null) {
+ identityAddress = deviceProp.getIdentityAddress();
+ }
+ identityAddressType = deviceProp.getIdentityAddressType();
+ } else {
+ if (Flags.identityAddressNullIfNotKnown()) {
+ identityAddress = null;
+ } else {
+ identityAddress = address;
+ }
+ }
+
+ return new BluetoothAddress(identityAddress, identityAddressType);
+ }
+
private static class CallerInfo {
public String callerPackageName;
public UserHandle user;
@@ -6355,14 +6429,7 @@ public class AdapterService extends Service {
long idleTime,
long energyUsed,
UidTraffic[] data) {
- if (Flags.btSystemContextReport()) {
- energyInfoCallbackInternal(
- status, ctrlState, txTime, rxTime, idleTime, energyUsed, data);
- } else if (ctrlState >= BluetoothActivityEnergyInfo.BT_STACK_STATE_INVALID
- && ctrlState <= BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_IDLE) {
- energyInfoCallbackInternal(
- status, ctrlState, txTime, rxTime, idleTime, energyUsed, data);
- }
+ energyInfoCallbackInternal(status, ctrlState, txTime, rxTime, idleTime, energyUsed, data);
Log.v(
TAG,
"energyInfoCallback()"
@@ -7106,4 +7173,26 @@ public class AdapterService extends Service {
Log.e(TAG, "Error happened while removing contents: ", e);
}
}
+
+ /** Get the number of the supported offloaded LE COC sockets. */
+ public int getNumberOfSupportedOffloadedLeCocSockets() {
+ return mAdapterProperties.getNumberOfSupportedOffloadedLeCocSockets();
+ }
+
+ /** Check if the offloaded LE COC socket is supported. */
+ public boolean isLeCocSocketOffloadSupported() {
+ int val = getNumberOfSupportedOffloadedLeCocSockets();
+ return val > 0;
+ }
+
+ /** Get the number of the supported offloaded RFCOMM sockets. */
+ public int getNumberOfSupportedOffloadedRfcommSockets() {
+ return mAdapterProperties.getNumberOfSupportedOffloadedRfcommSockets();
+ }
+
+ /** Check if the offloaded RFCOMM socket is supported. */
+ public boolean isRfcommSocketOffloadSupported() {
+ int val = getNumberOfSupportedOffloadedRfcommSockets();
+ return val > 0;
+ }
}
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterSuspend.java b/android/app/src/com/android/bluetooth/btservice/AdapterSuspend.java
index 751bb3d6dc..857121b1f9 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterSuspend.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterSuspend.java
@@ -21,16 +21,19 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static java.util.Objects.requireNonNull;
-import android.hardware.display.DisplayManager;
+import android.annotation.NonNull;
+import android.hardware.devicestate.DeviceState;
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
-import android.view.Display;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.RequiresApi;
-import java.util.Arrays;
+import com.android.internal.annotations.VisibleForTesting;
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public class AdapterSuspend {
private static final String TAG = "BtAdapterSuspend";
@@ -39,42 +42,78 @@ public class AdapterSuspend {
private static final long MASK_DISCONNECT_CMPLT = 1 << 4;
private static final long MASK_MODE_CHANGE = 1 << 19;
- private boolean mSuspended = false;
+ private static final String DEVICE_STATE_LAPTOP = "LAPTOP";
+ private static final String DEVICE_STATE_TABLET = "TABLET";
+ private static final String DEVICE_STATE_DOCKED = "DOCKED";
+ private static final String DEVICE_STATE_CLOSED = "CLOSED";
+ private static final String DEVICE_STATE_DISPLAY_OFF = "DISPLAY_OFF";
- private final AdapterNativeInterface mAdapterNativeInterface;
- private final Looper mLooper;
- private final DisplayManager mDisplayManager;
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {}
+ private final DeviceStateManager mDeviceStateManager;
+ public final DeviceStateManager.DeviceStateCallback mDeviceStateCallback =
+ new DeviceStateManager.DeviceStateCallback() {
@Override
- public void onDisplayRemoved(int displayId) {}
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
+ String nextState = state.getName();
+ Log.d(TAG, "Handle state transition: " + mCurrentState + " => " + nextState);
+ if (mCurrentState.equals("None")) {
+ mCurrentState = nextState;
+ Log.i(TAG, "Initialize device state to " + nextState);
+ return;
+ }
- @Override
- public void onDisplayChanged(int displayId) {
- if (isScreenOn()) {
- handleResume();
- } else {
- handleSuspend();
+ switch (nextState) {
+ case DEVICE_STATE_CLOSED -> {
+ switch (mCurrentState) {
+ case DEVICE_STATE_DISPLAY_OFF ->
+ Log.d(TAG, "No action for state " + nextState);
+ default -> handleSuspend(false);
+ }
+ }
+ case DEVICE_STATE_DISPLAY_OFF -> {
+ switch (mCurrentState) {
+ case DEVICE_STATE_TABLET -> handleSuspend(false);
+ case DEVICE_STATE_DOCKED, DEVICE_STATE_LAPTOP ->
+ handleSuspend(true);
+ default -> Log.d(TAG, "No action for state " + nextState);
+ }
+ }
+ case DEVICE_STATE_LAPTOP, DEVICE_STATE_DOCKED, DEVICE_STATE_TABLET -> {
+ switch (mCurrentState) {
+ case DEVICE_STATE_CLOSED, DEVICE_STATE_DISPLAY_OFF ->
+ handleResume();
+ default -> Log.d(TAG, "No action for state " + nextState);
+ }
+ }
+ default -> {
+ Log.wtf(TAG, "Unknown state transition to " + nextState);
+ return;
+ }
}
+ mCurrentState = nextState;
}
};
+ private boolean mSuspended = false;
+
+ // Value should be initialized when registering the mDeviceStateCallback.
+ private String mCurrentState = "None";
+
+ private final AdapterNativeInterface mAdapterNativeInterface;
+
public AdapterSuspend(
AdapterNativeInterface adapterNativeInterface,
Looper looper,
- DisplayManager displayManager) {
+ DeviceStateManager deviceStateManager) {
mAdapterNativeInterface = requireNonNull(adapterNativeInterface);
- mLooper = requireNonNull(looper);
- mDisplayManager = requireNonNull(displayManager);
+ Handler handler = new Handler(requireNonNull(looper));
- mDisplayManager.registerDisplayListener(mDisplayListener, new Handler(mLooper));
+ mDeviceStateManager = requireNonNull(deviceStateManager);
+ mDeviceStateManager.registerCallback(handler::post, mDeviceStateCallback);
}
void cleanup() {
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ mDeviceStateManager.unregisterCallback(mDeviceStateCallback);
}
@VisibleForTesting
@@ -82,13 +121,8 @@ public class AdapterSuspend {
return mSuspended;
}
- private boolean isScreenOn() {
- return Arrays.stream(mDisplayManager.getDisplays())
- .anyMatch(display -> display.getState() == Display.STATE_ON);
- }
-
@VisibleForTesting
- void handleSuspend() {
+ void handleSuspend(boolean allowWakeByHid) {
if (mSuspended) {
return;
}
@@ -106,7 +140,11 @@ public class AdapterSuspend {
mAdapterNativeInterface.clearEventFilter();
mAdapterNativeInterface.clearFilterAcceptList();
mAdapterNativeInterface.disconnectAllAcls();
- mAdapterNativeInterface.allowWakeByHid();
+
+ if (allowWakeByHid) {
+ mAdapterNativeInterface.allowWakeByHid();
+ Log.i(TAG, "configure wake by hid");
+ }
Log.i(TAG, "ready to suspend");
}
diff --git a/android/app/src/com/android/bluetooth/btservice/BluetoothHciVendorSpecificNativeInterface.java b/android/app/src/com/android/bluetooth/btservice/BluetoothHciVendorSpecificNativeInterface.java
index 7acf26f360..dc3517171c 100644
--- a/android/app/src/com/android/bluetooth/btservice/BluetoothHciVendorSpecificNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/btservice/BluetoothHciVendorSpecificNativeInterface.java
@@ -16,16 +16,39 @@
package com.android.bluetooth.btservice;
-class BluetoothHciVendorSpecificNativeInterface {
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+public class BluetoothHciVendorSpecificNativeInterface {
private static final String TAG = "BluetoothHciVendorSpecificNativeInterface";
- private final BluetoothHciVendorSpecificDispatcher mDispatcher;
- public BluetoothHciVendorSpecificNativeInterface(
- BluetoothHciVendorSpecificDispatcher dispatcher) {
- mDispatcher = dispatcher;
+ @GuardedBy("INSTANCE_LOCK")
+ private static BluetoothHciVendorSpecificNativeInterface sInstance;
+
+ private static final Object INSTANCE_LOCK = new Object();
+
+ /** Get singleton instance. */
+ public static BluetoothHciVendorSpecificNativeInterface getInstance() {
+ synchronized (INSTANCE_LOCK) {
+ if (sInstance == null) {
+ sInstance = new BluetoothHciVendorSpecificNativeInterface();
+ }
+ return sInstance;
+ }
}
- void init() {
+ /** Set singleton instance. */
+ @VisibleForTesting
+ static void setInstance(BluetoothHciVendorSpecificNativeInterface instance) {
+ synchronized (INSTANCE_LOCK) {
+ sInstance = instance;
+ }
+ }
+
+ private BluetoothHciVendorSpecificDispatcher mDispatcher;
+
+ void init(BluetoothHciVendorSpecificDispatcher dispatcher) {
+ mDispatcher = dispatcher;
initNative();
}
diff --git a/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java b/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
index d3062c3707..d5309f6ad7 100644
--- a/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
+++ b/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
+import android.bluetooth.BluetoothSocketSettings;
import android.bluetooth.IBluetoothSocketManager;
import android.content.AttributionSource;
import android.os.Binder;
@@ -86,7 +87,82 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub {
Utils.uuidToByteArray(uuid),
port,
flag,
- Binder.getCallingUid()));
+ Binder.getCallingUid(),
+ 0,
+ "",
+ 0,
+ 0,
+ 0));
+ }
+
+ @Override
+ public ParcelFileDescriptor connectSocketwithOffload(
+ BluetoothDevice device,
+ int type,
+ ParcelUuid uuid,
+ int port,
+ int flag,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize) {
+
+ enforceActiveUser();
+
+ if (!Utils.checkConnectPermissionForPreflight(mService)) {
+ return null;
+ }
+
+ if (dataPath != BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ mService.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ enforceSocketOffloadSupport(type);
+ }
+ String brEdrAddress =
+ Flags.identityAddressNullIfNotKnown()
+ ? Utils.getBrEdrAddress(device)
+ : mService.getIdentityAddress(device.getAddress());
+
+ Log.i(
+ TAG,
+ "connectSocketwithOffload: device="
+ + device
+ + ", type="
+ + type
+ + ", uuid="
+ + uuid
+ + ", port="
+ + port
+ + ", from "
+ + Utils.getUidPidString()
+ + ", dataPath="
+ + dataPath
+ + ", socketName="
+ + socketName
+ + ", hubId="
+ + hubId
+ + ", endpointId="
+ + endpointId
+ + ", maximumPacketSize="
+ + maximumPacketSize);
+
+ return marshalFd(
+ mService.getNative()
+ .connectSocket(
+ Utils.getBytesFromAddress(
+ type == BluetoothSocket.TYPE_L2CAP_LE
+ ? device.getAddress()
+ : brEdrAddress),
+ type,
+ Utils.uuidToByteArray(uuid),
+ port,
+ flag,
+ Binder.getCallingUid(),
+ dataPath,
+ socketName,
+ hubId,
+ endpointId,
+ maximumPacketSize));
}
@Override
@@ -120,7 +196,75 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub {
Utils.uuidToByteArray(uuid),
port,
flag,
- Binder.getCallingUid()));
+ Binder.getCallingUid(),
+ 0,
+ "",
+ 0,
+ 0,
+ 0));
+ }
+
+ @Override
+ public ParcelFileDescriptor createSocketChannelWithOffload(
+ int type,
+ String serviceName,
+ ParcelUuid uuid,
+ int port,
+ int flag,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize) {
+
+ enforceActiveUser();
+
+ if (!Utils.checkConnectPermissionForPreflight(mService)) {
+ return null;
+ }
+
+ if (dataPath != BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ mService.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ enforceSocketOffloadSupport(type);
+ }
+
+ Log.i(
+ TAG,
+ "createSocketChannelWithOffload: type="
+ + type
+ + ", serviceName="
+ + serviceName
+ + ", uuid="
+ + uuid
+ + ", port="
+ + port
+ + ", from "
+ + Utils.getUidPidString()
+ + ", dataPath="
+ + dataPath
+ + ", socketName="
+ + socketName
+ + ", hubId="
+ + hubId
+ + ", endpointId="
+ + endpointId
+ + ", maximumPacketSize="
+ + maximumPacketSize);
+
+ return marshalFd(
+ mService.getNative()
+ .createSocketChannel(
+ type,
+ serviceName,
+ Utils.uuidToByteArray(uuid),
+ port,
+ flag,
+ Binder.getCallingUid(),
+ dataPath,
+ socketName,
+ hubId,
+ endpointId,
+ maximumPacketSize));
}
@Override
@@ -169,6 +313,14 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub {
}
}
+ private void enforceSocketOffloadSupport(int type) {
+ if (!(type == BluetoothSocket.TYPE_LE && mService.isLeCocSocketOffloadSupported())
+ && !(type == BluetoothSocket.TYPE_RFCOMM
+ && mService.isRfcommSocketOffloadSupported())) {
+ throw new IllegalStateException("Unsupported socket type for offload " + type);
+ }
+ }
+
private static ParcelFileDescriptor marshalFd(int fd) {
if (fd == INVALID_FD) {
return null;
diff --git a/android/app/src/com/android/bluetooth/btservice/Config.java b/android/app/src/com/android/bluetooth/btservice/Config.java
index f5e9b8cd1b..f372983d7e 100644
--- a/android/app/src/com/android/bluetooth/btservice/Config.java
+++ b/android/app/src/com/android/bluetooth/btservice/Config.java
@@ -30,7 +30,6 @@ import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
import com.android.bluetooth.bas.BatteryService;
import com.android.bluetooth.bass_client.BassClientService;
import com.android.bluetooth.csip.CsipSetCoordinatorService;
-import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.gatt.GattService;
import com.android.bluetooth.hap.HapClientService;
import com.android.bluetooth.hearingaid.HearingAidService;
@@ -86,105 +85,45 @@ public class Config {
};
/** List of profile services with the profile-supported resource flag and bit mask. */
- private static final ProfileConfig[] PROFILE_SERVICES_AND_FLAGS;
-
- static {
- if (Flags.leaudioSynchronizeStart()) {
- PROFILE_SERVICES_AND_FLAGS =
- new ProfileConfig[] {
- // Prioritize GattService startup by making it the first Profile to
- // boot. This resolves dependency issues for some Profiles.
- new ProfileConfig(GattService.isEnabled(), BluetoothProfile.GATT),
- new ProfileConfig(A2dpService.isEnabled(), BluetoothProfile.A2DP),
- new ProfileConfig(A2dpSinkService.isEnabled(), BluetoothProfile.A2DP_SINK),
- new ProfileConfig(AvrcpTargetService.isEnabled(), BluetoothProfile.AVRCP),
- new ProfileConfig(
- AvrcpControllerService.isEnabled(),
- BluetoothProfile.AVRCP_CONTROLLER),
- new ProfileConfig(
- BassClientService.isEnabled(),
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT),
- new ProfileConfig(BatteryService.isEnabled(), BluetoothProfile.BATTERY),
- new ProfileConfig(
- CsipSetCoordinatorService.isEnabled(),
- BluetoothProfile.CSIP_SET_COORDINATOR),
- new ProfileConfig(
- HapClientService.isEnabled(), BluetoothProfile.HAP_CLIENT),
- new ProfileConfig(HeadsetService.isEnabled(), BluetoothProfile.HEADSET),
- new ProfileConfig(
- HeadsetClientService.isEnabled(), BluetoothProfile.HEADSET_CLIENT),
- new ProfileConfig(
- HearingAidService.isEnabled(), BluetoothProfile.HEARING_AID),
- new ProfileConfig(
- HidDeviceService.isEnabled(), BluetoothProfile.HID_DEVICE),
- new ProfileConfig(HidHostService.isEnabled(), BluetoothProfile.HID_HOST),
- new ProfileConfig(TbsService.isEnabled(), BluetoothProfile.LE_CALL_CONTROL),
- new ProfileConfig(BluetoothMapService.isEnabled(), BluetoothProfile.MAP),
- new ProfileConfig(
- MapClientService.isEnabled(), BluetoothProfile.MAP_CLIENT),
- new ProfileConfig(McpService.isEnabled(), BluetoothProfile.MCP_SERVER),
- new ProfileConfig(BluetoothOppService.isEnabled(), BluetoothProfile.OPP),
- new ProfileConfig(PanService.isEnabled(), BluetoothProfile.PAN),
- new ProfileConfig(BluetoothPbapService.isEnabled(), BluetoothProfile.PBAP),
- new ProfileConfig(
- PbapClientService.isEnabled(), BluetoothProfile.PBAP_CLIENT),
- new ProfileConfig(SapService.isEnabled(), BluetoothProfile.SAP),
- new ProfileConfig(
- VolumeControlService.isEnabled(), BluetoothProfile.VOLUME_CONTROL),
- new ProfileConfig(LeAudioService.isEnabled(), BluetoothProfile.LE_AUDIO),
- new ProfileConfig(
- LeAudioService.isBroadcastEnabled(),
- BluetoothProfile.LE_AUDIO_BROADCAST),
- };
- } else {
- PROFILE_SERVICES_AND_FLAGS =
- new ProfileConfig[] {
- // Prioritize GattService startup by making it the first Profile to
- // boot. This resolves dependency issues for some Profiles.
- new ProfileConfig(GattService.isEnabled(), BluetoothProfile.GATT),
- new ProfileConfig(A2dpService.isEnabled(), BluetoothProfile.A2DP),
- new ProfileConfig(A2dpSinkService.isEnabled(), BluetoothProfile.A2DP_SINK),
- new ProfileConfig(AvrcpTargetService.isEnabled(), BluetoothProfile.AVRCP),
- new ProfileConfig(
- AvrcpControllerService.isEnabled(),
- BluetoothProfile.AVRCP_CONTROLLER),
- new ProfileConfig(
- BassClientService.isEnabled(),
- BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT),
- new ProfileConfig(BatteryService.isEnabled(), BluetoothProfile.BATTERY),
- new ProfileConfig(
- CsipSetCoordinatorService.isEnabled(),
- BluetoothProfile.CSIP_SET_COORDINATOR),
- new ProfileConfig(
- HapClientService.isEnabled(), BluetoothProfile.HAP_CLIENT),
- new ProfileConfig(HeadsetService.isEnabled(), BluetoothProfile.HEADSET),
- new ProfileConfig(
- HeadsetClientService.isEnabled(), BluetoothProfile.HEADSET_CLIENT),
- new ProfileConfig(
- HearingAidService.isEnabled(), BluetoothProfile.HEARING_AID),
- new ProfileConfig(
- HidDeviceService.isEnabled(), BluetoothProfile.HID_DEVICE),
- new ProfileConfig(HidHostService.isEnabled(), BluetoothProfile.HID_HOST),
- new ProfileConfig(LeAudioService.isEnabled(), BluetoothProfile.LE_AUDIO),
- new ProfileConfig(
- LeAudioService.isBroadcastEnabled(),
- BluetoothProfile.LE_AUDIO_BROADCAST),
- new ProfileConfig(TbsService.isEnabled(), BluetoothProfile.LE_CALL_CONTROL),
- new ProfileConfig(BluetoothMapService.isEnabled(), BluetoothProfile.MAP),
- new ProfileConfig(
- MapClientService.isEnabled(), BluetoothProfile.MAP_CLIENT),
- new ProfileConfig(McpService.isEnabled(), BluetoothProfile.MCP_SERVER),
- new ProfileConfig(BluetoothOppService.isEnabled(), BluetoothProfile.OPP),
- new ProfileConfig(PanService.isEnabled(), BluetoothProfile.PAN),
- new ProfileConfig(BluetoothPbapService.isEnabled(), BluetoothProfile.PBAP),
- new ProfileConfig(
- PbapClientService.isEnabled(), BluetoothProfile.PBAP_CLIENT),
- new ProfileConfig(SapService.isEnabled(), BluetoothProfile.SAP),
- new ProfileConfig(
- VolumeControlService.isEnabled(), BluetoothProfile.VOLUME_CONTROL),
- };
- }
- }
+ private static final ProfileConfig[] PROFILE_SERVICES_AND_FLAGS =
+ new ProfileConfig[] {
+ // Prioritize GattService startup by making it the first Profile to
+ // boot. This resolves dependency issues for some Profiles.
+ new ProfileConfig(GattService.isEnabled(), BluetoothProfile.GATT),
+ new ProfileConfig(A2dpService.isEnabled(), BluetoothProfile.A2DP),
+ new ProfileConfig(A2dpSinkService.isEnabled(), BluetoothProfile.A2DP_SINK),
+ new ProfileConfig(AvrcpTargetService.isEnabled(), BluetoothProfile.AVRCP),
+ new ProfileConfig(
+ AvrcpControllerService.isEnabled(), BluetoothProfile.AVRCP_CONTROLLER),
+ new ProfileConfig(
+ BassClientService.isEnabled(),
+ BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT),
+ new ProfileConfig(BatteryService.isEnabled(), BluetoothProfile.BATTERY),
+ new ProfileConfig(
+ CsipSetCoordinatorService.isEnabled(),
+ BluetoothProfile.CSIP_SET_COORDINATOR),
+ new ProfileConfig(HapClientService.isEnabled(), BluetoothProfile.HAP_CLIENT),
+ new ProfileConfig(HeadsetService.isEnabled(), BluetoothProfile.HEADSET),
+ new ProfileConfig(
+ HeadsetClientService.isEnabled(), BluetoothProfile.HEADSET_CLIENT),
+ new ProfileConfig(HearingAidService.isEnabled(), BluetoothProfile.HEARING_AID),
+ new ProfileConfig(HidDeviceService.isEnabled(), BluetoothProfile.HID_DEVICE),
+ new ProfileConfig(HidHostService.isEnabled(), BluetoothProfile.HID_HOST),
+ new ProfileConfig(TbsService.isEnabled(), BluetoothProfile.LE_CALL_CONTROL),
+ new ProfileConfig(BluetoothMapService.isEnabled(), BluetoothProfile.MAP),
+ new ProfileConfig(MapClientService.isEnabled(), BluetoothProfile.MAP_CLIENT),
+ new ProfileConfig(McpService.isEnabled(), BluetoothProfile.MCP_SERVER),
+ new ProfileConfig(BluetoothOppService.isEnabled(), BluetoothProfile.OPP),
+ new ProfileConfig(PanService.isEnabled(), BluetoothProfile.PAN),
+ new ProfileConfig(BluetoothPbapService.isEnabled(), BluetoothProfile.PBAP),
+ new ProfileConfig(PbapClientService.isEnabled(), BluetoothProfile.PBAP_CLIENT),
+ new ProfileConfig(SapService.isEnabled(), BluetoothProfile.SAP),
+ new ProfileConfig(
+ VolumeControlService.isEnabled(), BluetoothProfile.VOLUME_CONTROL),
+ new ProfileConfig(LeAudioService.isEnabled(), BluetoothProfile.LE_AUDIO),
+ new ProfileConfig(
+ LeAudioService.isBroadcastEnabled(), BluetoothProfile.LE_AUDIO_BROADCAST),
+ };
/** A test function to allow for dynamic enabled */
@VisibleForTesting
diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index 376b19c321..2d87a8da2e 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -1183,14 +1183,13 @@ public class RemoteDevices {
}
void addressConsolidateCallback(byte[] mainAddress, byte[] secondaryAddress) {
+ DeviceProperties deviceProperties;
BluetoothDevice device = getDevice(mainAddress);
if (device == null) {
- errorLog(
- "addressConsolidateCallback: device is NULL, address="
- + Utils.getRedactedAddressStringFromByte(mainAddress)
- + ", secondaryAddress="
- + Utils.getRedactedAddressStringFromByte(secondaryAddress));
- return;
+ deviceProperties = addDeviceProperties(mainAddress);
+ device = deviceProperties.getDevice();
+ } else {
+ deviceProperties = getDeviceProperties(device);
}
Log.d(
TAG,
@@ -1199,7 +1198,6 @@ public class RemoteDevices {
+ ", secondaryAddress:"
+ Utils.getRedactedAddressStringFromByte(secondaryAddress));
- DeviceProperties deviceProperties = getDeviceProperties(device);
deviceProperties.setIsConsolidated(true);
deviceProperties.setDeviceType(BluetoothDevice.DEVICE_TYPE_DUAL);
deviceProperties.setIdentityAddress(Utils.getAddressStringFromByte(secondaryAddress));
@@ -1217,16 +1215,13 @@ public class RemoteDevices {
*/
void leAddressAssociateCallback(
byte[] mainAddress, byte[] secondaryAddress, int identityAddressTypeFromNative) {
+ DeviceProperties deviceProperties;
BluetoothDevice device = getDevice(mainAddress);
if (device == null) {
- errorLog(
- "leAddressAssociateCallback: device is NULL, address="
- + Utils.getRedactedAddressStringFromByte(mainAddress)
- + ", secondaryAddress="
- + Utils.getRedactedAddressStringFromByte(secondaryAddress)
- + ", identityAddressTypeFromNative="
- + identityAddressTypeFromNative);
- return;
+ deviceProperties = addDeviceProperties(mainAddress);
+ device = deviceProperties.getDevice();
+ } else {
+ deviceProperties = getDeviceProperties(device);
}
Log.d(
TAG,
@@ -1237,7 +1232,6 @@ public class RemoteDevices {
+ ", identityAddressTypeFromNative="
+ identityAddressTypeFromNative);
- DeviceProperties deviceProperties = getDeviceProperties(device);
deviceProperties.setIdentityAddress(Utils.getAddressStringFromByte(secondaryAddress));
deviceProperties.setIdentityAddressTypeFromNative(identityAddressTypeFromNative);
}
diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface.java
index 5fe00aaeb0..1247cb7330 100644
--- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorNativeInterface.java
@@ -17,12 +17,13 @@
package com.android.bluetooth.csip;
+import static java.util.Objects.requireNonNull;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.util.Log;
import com.android.bluetooth.Utils;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.UUID;
@@ -30,83 +31,29 @@ import java.util.UUID;
/** CSIP Set Coordinator role native interface */
public class CsipSetCoordinatorNativeInterface {
private static final String TAG = "CsipSetCoordinatorNativeInterface";
- private BluetoothAdapter mAdapter;
-
- @GuardedBy("INSTANCE_LOCK")
- private static CsipSetCoordinatorNativeInterface sInstance;
-
- private static final Object INSTANCE_LOCK = new Object();
-
- private CsipSetCoordinatorNativeInterface() {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- if (mAdapter == null) {
- Log.wtf(TAG, "No Bluetooth Adapter Available");
- }
- }
-
- /** Get singleton instance. */
- public static CsipSetCoordinatorNativeInterface getInstance() {
- synchronized (INSTANCE_LOCK) {
- if (sInstance == null) {
- sInstance = new CsipSetCoordinatorNativeInterface();
- }
- return sInstance;
- }
- }
+ private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
- /** Set singleton instance. */
- @VisibleForTesting
- public static void setInstance(CsipSetCoordinatorNativeInterface instance) {
- synchronized (INSTANCE_LOCK) {
- sInstance = instance;
- }
+ CsipSetCoordinatorNativeInterface() {
+ requireNonNull(mAdapter);
}
- /**
- * Initializes the native interface.
- *
- * <p>priorities to configure.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void init() {
+ void init() {
initNative();
}
- /** Cleanup the native interface. */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void cleanup() {
+ void cleanup() {
cleanupNative();
}
- /**
- * Initiates CsipSetCoordinator connection to a remote device.
- *
- * @param device the remote device
- * @return true on success, otherwise false.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public boolean connect(BluetoothDevice device) {
+ boolean connect(BluetoothDevice device) {
return connectNative(getByteAddress(device));
}
- /**
- * Disconnects CsipSetCoordinator from a remote device.
- *
- * @param device the remote device
- * @return true on success, otherwise false.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public boolean disconnect(BluetoothDevice device) {
+ boolean disconnect(BluetoothDevice device) {
return disconnectNative(getByteAddress(device));
}
- /**
- * Get the device by the address
- *
- * @return the device
- */
- @VisibleForTesting
- public BluetoothDevice getDevice(byte[] address) {
+ BluetoothDevice getDevice(byte[] address) {
return mAdapter.getRemoteDevice(address);
}
diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
index f1cdefc1b2..a206cee2a7 100644
--- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
+++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
@@ -20,6 +20,9 @@ package com.android.bluetooth.csip;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+import static java.util.Objects.requireNonNull;
+import static java.util.Objects.requireNonNullElseGet;
+
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,9 +36,7 @@ import android.bluetooth.IBluetoothCsipSetCoordinator;
import android.bluetooth.IBluetoothCsipSetCoordinatorCallback;
import android.bluetooth.IBluetoothCsipSetCoordinatorLockCallback;
import android.content.AttributionSource;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -60,7 +61,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -76,15 +76,13 @@ public class CsipSetCoordinatorService extends ProfileService {
private static CsipSetCoordinatorService sCsipSetCoordinatorService;
- private Handler mHandler = null;
-
- private AdapterService mAdapterService;
- private LeAudioService mLeAudioService;
- private DatabaseManager mDatabaseManager;
- private HandlerThread mStateMachinesThread;
- @VisibleForTesting ServiceFactory mServiceFactory = new ServiceFactory();
-
- @VisibleForTesting CsipSetCoordinatorNativeInterface mCsipSetCoordinatorNativeInterface;
+ private final AdapterService mAdapterService;
+ private final DatabaseManager mDatabaseManager;
+ private final Handler mHandler;
+ private final HandlerThread mStateMachinesThread;
+ private final Looper mStateMachinesLooper;
+ private final CsipSetCoordinatorNativeInterface mNativeInterface;
+ private final ServiceFactory mServiceFactory;
@GuardedBy("mStateMachines")
private final Map<BluetoothDevice, CsipSetCoordinatorStateMachine> mStateMachines =
@@ -103,66 +101,53 @@ public class CsipSetCoordinatorService extends ProfileService {
private final Map<Integer, Pair<UUID, IBluetoothCsipSetCoordinatorLockCallback>> mLocks =
new ConcurrentHashMap<>();
- public CsipSetCoordinatorService(Context ctx) {
- super(ctx);
- }
-
- public static boolean isEnabled() {
- return BluetoothProperties.isProfileCsipSetCoordinatorEnabled().orElse(false);
- }
+ private LeAudioService mLeAudioService;
- @Override
- protected IProfileServiceBinder initBinder() {
- return new BluetoothCsisBinder(this);
+ public CsipSetCoordinatorService(AdapterService adapterService) {
+ this(adapterService, null, null, new ServiceFactory());
}
- @Override
- public void start() {
- Log.d(TAG, "start()");
- if (sCsipSetCoordinatorService != null) {
- throw new IllegalStateException("start() called twice");
- }
-
- // Get AdapterService, DatabaseManager, CsipSetCoordinatorNativeInterface.
- // None of them can be null.
- mAdapterService =
- Objects.requireNonNull(
- AdapterService.getAdapterService(),
- "AdapterService cannot be null when CsipSetCoordinatorService starts");
- mDatabaseManager =
- Objects.requireNonNull(
- mAdapterService.getDatabase(),
- "DatabaseManager cannot be null when CsipSetCoordinatorService starts");
- mCsipSetCoordinatorNativeInterface =
- Objects.requireNonNull(
- CsipSetCoordinatorNativeInterface.getInstance(),
- "CsipSetCoordinatorNativeInterface cannot be null when"
- .concat("CsipSetCoordinatorService starts"));
-
- // Setup Handler.
- mHandler = new Handler(Looper.getMainLooper());
+ @VisibleForTesting
+ CsipSetCoordinatorService(
+ AdapterService adapterService,
+ Looper looper,
+ CsipSetCoordinatorNativeInterface nativeInterface,
+ ServiceFactory serviceFactory) {
+ super(requireNonNull(adapterService));
+ mAdapterService = adapterService;
+ mDatabaseManager = requireNonNull(mAdapterService.getDatabase());
+ mNativeInterface =
+ requireNonNullElseGet(
+ nativeInterface, () -> new CsipSetCoordinatorNativeInterface());
+ mServiceFactory = requireNonNull(serviceFactory);
+ if (looper == null) {
+ mHandler = new Handler(requireNonNull(Looper.getMainLooper()));
+ mStateMachinesThread = new HandlerThread("CsipSetCoordinatorService.StateMachines");
+ mStateMachinesThread.start();
+ mStateMachinesLooper = mStateMachinesThread.getLooper();
+ } else {
+ mHandler = new Handler(looper);
+ mStateMachinesThread = null;
+ mStateMachinesLooper = looper;
+ }
// Get LE Audio service (can be null)
mLeAudioService = mServiceFactory.getLeAudioService();
- synchronized (mStateMachines) {
- mStateMachines.clear();
- }
-
- // Start handler thread for state machines
- mStateMachinesThread = new HandlerThread("CsipSetCoordinatorService.StateMachines");
- mStateMachinesThread.start();
-
- // Setup broadcast receivers
- IntentFilter filter = new IntentFilter();
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-
// Mark service as started
setCsipSetCoordinatorService(this);
// Initialize native interface
- mCsipSetCoordinatorNativeInterface.init();
+ mNativeInterface.init();
+ }
+
+ public static boolean isEnabled() {
+ return BluetoothProperties.isProfileCsipSetCoordinatorEnabled().orElse(false);
+ }
+
+ @Override
+ protected IProfileServiceBinder initBinder() {
+ return new BluetoothCsisBinder(this);
}
@Override
@@ -174,8 +159,7 @@ public class CsipSetCoordinatorService extends ProfileService {
}
// Cleanup native interface
- mCsipSetCoordinatorNativeInterface.cleanup();
- mCsipSetCoordinatorNativeInterface = null;
+ mNativeInterface.cleanup();
// Mark service as stopped
setCsipSetCoordinatorService(null);
@@ -193,17 +177,13 @@ public class CsipSetCoordinatorService extends ProfileService {
try {
mStateMachinesThread.quitSafely();
mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS);
- mStateMachinesThread = null;
} catch (InterruptedException e) {
// Do not rethrow as we are shutting down anyway
}
}
// Unregister Handler and stop all queued messages.
- if (mHandler != null) {
- mHandler.removeCallbacksAndMessages(null);
- mHandler = null;
- }
+ mHandler.removeCallbacksAndMessages(null);
mDeviceGroupIdRankMap.clear();
mCallbacks.clear();
@@ -213,10 +193,6 @@ public class CsipSetCoordinatorService extends ProfileService {
mGroupIdToUuidMap.clear();
mLocks.clear();
-
- // Clear AdapterService, CsipSetCoordinatorNativeInterface
- mCsipSetCoordinatorNativeInterface = null;
- mAdapterService = null;
}
@Override
@@ -515,7 +491,7 @@ public class CsipSetCoordinatorService extends ProfileService {
}
Log.d(TAG, "lockGroup(): locking group: " + groupId);
- mCsipSetCoordinatorNativeInterface.groupLockSet(groupId, true);
+ mNativeInterface.groupLockSet(groupId, true);
return uuid;
}
@@ -536,7 +512,7 @@ public class CsipSetCoordinatorService extends ProfileService {
Pair<UUID, IBluetoothCsipSetCoordinatorLockCallback> uuidCbPair = entry.getValue();
if (uuidCbPair.first.equals(lockUuid)) {
Log.d(TAG, "unlockGroup(): unlocking ... " + lockUuid);
- mCsipSetCoordinatorNativeInterface.groupLockSet(entry.getKey(), false);
+ mNativeInterface.groupLockSet(entry.getKey(), false);
return;
}
}
@@ -803,13 +779,13 @@ public class CsipSetCoordinatorService extends ProfileService {
Log.d(TAG, "notifySetMemberAvailable: " + device + ", " + groupId);
/* Sent intent as well */
- Intent intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId);
-
- intent.addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ Intent intent =
+ new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE)
+ .putExtra(BluetoothDevice.EXTRA_DEVICE, device)
+ .putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId)
+ .addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
sendOrderedBroadcast(intent, BLUETOOTH_PRIVILEGED);
/* Notify registered parties */
@@ -820,18 +796,9 @@ public class CsipSetCoordinatorService extends ProfileService {
BluetoothDevice device = stackEvent.device;
Log.d(TAG, "Message from native: " + stackEvent);
- Intent intent = null;
int groupId = stackEvent.valueInt1;
if (stackEvent.type == CsipSetCoordinatorStackEvent.EVENT_TYPE_DEVICE_AVAILABLE) {
- Objects.requireNonNull(device);
-
- intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_DEVICE_AVAILABLE);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, stackEvent.device);
- intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId);
- intent.putExtra(
- BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_SIZE, stackEvent.valueInt2);
- intent.putExtra(
- BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID, stackEvent.valueUuid1);
+ requireNonNull(device);
handleDeviceAvailable(
device,
@@ -839,9 +806,24 @@ public class CsipSetCoordinatorService extends ProfileService {
stackEvent.valueInt3,
stackEvent.valueUuid1,
stackEvent.valueInt2);
+
+ Intent intent =
+ new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_DEVICE_AVAILABLE)
+ .putExtra(BluetoothDevice.EXTRA_DEVICE, stackEvent.device)
+ .putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId)
+ .putExtra(
+ BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_SIZE,
+ stackEvent.valueInt2)
+ .putExtra(
+ BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID,
+ stackEvent.valueUuid1)
+ .addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ sendOrderedBroadcast(intent, BLUETOOTH_PRIVILEGED);
} else if (stackEvent.type
== CsipSetCoordinatorStackEvent.EVENT_TYPE_SET_MEMBER_AVAILABLE) {
- Objects.requireNonNull(device);
+ requireNonNull(device);
if (!mFoundSetMemberToGroupId.containsKey(device)) {
mFoundSetMemberToGroupId.put(device, groupId);
}
@@ -854,13 +836,6 @@ public class CsipSetCoordinatorService extends ProfileService {
handleGroupLockChanged(groupId, lock_status, lock_state);
}
- if (intent != null) {
- intent.addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- sendOrderedBroadcast(intent, BLUETOOTH_PRIVILEGED);
- }
-
synchronized (mStateMachines) {
CsipSetCoordinatorStateMachine sm = mStateMachines.get(device);
@@ -900,10 +875,7 @@ public class CsipSetCoordinatorService extends ProfileService {
Log.d(TAG, "Creating a new state machine for " + device);
sm =
CsipSetCoordinatorStateMachine.make(
- device,
- this,
- mCsipSetCoordinatorNativeInterface,
- mStateMachinesThread.getLooper());
+ device, this, mNativeInterface, mStateMachinesLooper);
mStateMachines.put(device, sm);
return sm;
}
@@ -911,16 +883,6 @@ public class CsipSetCoordinatorService extends ProfileService {
/** Process a change in the bonding state for a device */
public void handleBondStateChanged(BluetoothDevice device, int fromState, int toState) {
- if (mHandler == null) {
- Log.e(
- TAG,
- "mHandler is null, service is stopped. Ignore Bond State for "
- + device
- + " to state: "
- + toState);
- return;
- }
-
mHandler.post(() -> bondStateChanged(device, toState));
}
@@ -982,15 +944,6 @@ public class CsipSetCoordinatorService extends ProfileService {
}
void handleConnectionStateChanged(BluetoothDevice device, int fromState, int toState) {
- if (mHandler == null) {
- Log.e(
- TAG,
- "mHandler is null, service is stopped. Ignore Connection State for "
- + device
- + " to state: "
- + toState);
- return;
- }
mHandler.post(() -> connectionStateChanged(device, fromState, toState));
}
@@ -1074,7 +1027,7 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public List<BluetoothDevice> getConnectedDevices(AttributionSource source) {
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1087,7 +1040,7 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(
int[] states, AttributionSource source) {
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1099,8 +1052,8 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public int getConnectionState(BluetoothDevice device, AttributionSource source) {
- Objects.requireNonNull(device, "device cannot be null");
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(device);
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1113,8 +1066,8 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public boolean setConnectionPolicy(
BluetoothDevice device, int connectionPolicy, AttributionSource source) {
- Objects.requireNonNull(device, "device cannot be null");
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(device);
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1126,8 +1079,8 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) {
- Objects.requireNonNull(device, "device cannot be null");
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(device);
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1142,8 +1095,8 @@ public class CsipSetCoordinatorService extends ProfileService {
int groupId,
@NonNull IBluetoothCsipSetCoordinatorLockCallback callback,
AttributionSource source) {
- Objects.requireNonNull(callback, "callback cannot be null");
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(callback);
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1156,8 +1109,8 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public void unlockGroup(@NonNull ParcelUuid lockUuid, AttributionSource source) {
- Objects.requireNonNull(lockUuid, "lockUuid cannot be null");
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(lockUuid);
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
@@ -1169,8 +1122,8 @@ public class CsipSetCoordinatorService extends ProfileService {
@Override
public List<Integer> getAllGroupIds(ParcelUuid uuid, AttributionSource source) {
- Objects.requireNonNull(uuid, "uuid cannot be null");
- Objects.requireNonNull(source, "source cannot be null");
+ requireNonNull(uuid);
+ requireNonNull(source);
CsipSetCoordinatorService service = getService(source);
if (service == null) {
diff --git a/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java b/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java
index 9706df37d7..65e401bd97 100644
--- a/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java
+++ b/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java
@@ -107,6 +107,12 @@ public class DistanceMeasurementManager {
"startDistanceMeasurement:"
+ (" device=" + params.getDevice())
+ (" method=" + params.getMethodId()));
+ if (!mAdapterService.isConnected(params.getDevice())) {
+ Log.e(TAG, "Device " + params.getDevice() + " is not connected");
+ invokeStartFail(
+ callback, params.getDevice(), BluetoothStatusCodes.ERROR_NO_LE_CONNECTION);
+ return;
+ }
String address = mAdapterService.getIdentityAddress(params.getDevice().getAddress());
if (address == null) {
address = params.getDevice().getAddress();
@@ -142,12 +148,13 @@ public class DistanceMeasurementManager {
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
return;
}
- if (!mAdapterService.isConnected(params.getDevice())) {
- Log.e(TAG, "Device " + params.getDevice() + " is not connected");
+ if (mAdapterService.getBondState(params.getDevice())
+ != BluetoothDevice.BOND_BONDED) {
+ Log.e(TAG, "StartDistanceMeasurement: the target device is not bonded.");
invokeStartFail(
callback,
params.getDevice(),
- BluetoothStatusCodes.ERROR_NO_LE_CONNECTION);
+ BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED);
return;
}
startCsTracker(tracker);
diff --git a/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java b/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java
index 5adbbf2b93..af59e0c8f6 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java
@@ -382,7 +382,7 @@ public class GattNativeInterface {
byte[] val,
int authReq);
- private native void gattSubrateRequestNative(
+ private native int gattSubrateRequestNative(
int clientIf,
String address,
int subrateMin,
@@ -570,7 +570,7 @@ public class GattNativeInterface {
}
/** Update connection parameter. */
- public void gattSubrateRequest(
+ public int gattSubrateRequest(
int clientIf,
String address,
int subrateMin,
@@ -578,7 +578,7 @@ public class GattNativeInterface {
int maxLatency,
int contNumber,
int supervisionTimeout) {
- gattSubrateRequestNative(
+ return gattSubrateRequestNative(
clientIf,
address,
subrateMin,
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index 2be39b6094..ef12680b72 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -56,6 +56,7 @@ import android.bluetooth.le.PeriodicAdvertisingParameters;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
+import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -180,9 +181,11 @@ public class GattService extends ProfileService {
private final AdapterService mAdapterService;
private final AdvertiseManager mAdvertiseManager;
private final GattNativeInterface mNativeInterface;
+ private final CompanionDeviceManager mCompanionDeviceManager;
private final DistanceMeasurementManager mDistanceMeasurementManager;
private final ActivityManager mActivityManager;
private final PackageManager mPackageManager;
+ private final HandlerThread mScanThread;
private Handler mTestModeHandler;
@@ -191,6 +194,7 @@ public class GattService extends ProfileService {
mAdapterService = adapterService;
mActivityManager = requireNonNull(getSystemService(ActivityManager.class));
mPackageManager = requireNonNull(mAdapterService.getPackageManager());
+ mCompanionDeviceManager = requireNonNull(getSystemService(CompanionDeviceManager.class));
mTransitionalScanHelper =
new TransitionalScanHelper(adapterService, this::isTestModeEnabled);
@@ -203,9 +207,11 @@ public class GattService extends ProfileService {
mAdvertiseManager = new AdvertiseManager(this);
if (!Flags.scanManagerRefactor()) {
- HandlerThread thread = new HandlerThread("BluetoothScanManager");
- thread.start();
- mTransitionalScanHelper.start(thread.getLooper());
+ mScanThread = new HandlerThread("BluetoothScanManager");
+ mScanThread.start();
+ mTransitionalScanHelper.start(mScanThread.getLooper());
+ } else {
+ mScanThread = null;
}
mDistanceMeasurementManager =
GattObjectsFactory.getInstance().createDistanceMeasurementManager(mAdapterService);
@@ -251,6 +257,9 @@ public class GattService extends ProfileService {
@Override
public void cleanup() {
Log.d(TAG, "cleanup()");
+ if (!Flags.scanManagerRefactor()) {
+ mScanThread.quitSafely();
+ }
mNativeInterface.cleanup();
mAdvertiseManager.cleanup();
mDistanceMeasurementManager.cleanup();
@@ -802,41 +811,39 @@ public class GattService extends ProfileService {
}
@Override
- public void subrateModeRequest(
+ public int subrateModeRequest(
int clientIf,
- String address,
+ BluetoothDevice device,
int subrateMode,
AttributionSource attributionSource) {
GattService service = getService();
if (service == null) {
- return;
+ return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
+ }
+ if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "subrateModeRequest")) {
+ return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
}
- service.subrateModeRequest(clientIf, address, subrateMode, attributionSource);
- }
- @Override
- public void leSubrateRequest(
- int clientIf,
- String address,
- int subrateMin,
- int subrateMax,
- int maxLatency,
- int contNumber,
- int supervisionTimeout,
- AttributionSource attributionSource) {
- GattService service = getService();
- if (service == null) {
- return;
+ if (!Utils.checkConnectPermissionForDataDelivery(
+ service, attributionSource, "GattService subrateModeRequest")) {
+ return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
}
- service.leSubrateRequest(
- clientIf,
- address,
- subrateMin,
- subrateMax,
- maxLatency,
- contNumber,
- supervisionTimeout,
- attributionSource);
+
+ Utils.enforceCdmAssociationIfNotBluetoothPrivileged(
+ service, service.mCompanionDeviceManager, attributionSource, device);
+
+ if (subrateMode < BluetoothGatt.SUBRATE_REQUEST_MODE_BALANCED
+ || subrateMode > BluetoothGatt.SUBRATE_REQUEST_MODE_LOW_POWER) {
+ throw new IllegalArgumentException("Subrate Mode not within valid range");
+ }
+
+ requireNonNull(device);
+ String address = device.getAddress();
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ throw new IllegalArgumentException("Invalid device address: " + address);
+ }
+
+ return service.subrateModeRequest(clientIf, device, subrateMode);
}
@Override
@@ -1334,6 +1341,13 @@ public class GattService extends ProfileService {
if (app != null) {
app.callback.onClientConnectionState(
status, clientIf, (status == BluetoothGatt.GATT_SUCCESS), address);
+ MetricsLogger.getInstance()
+ .logBluetoothEvent(
+ getDevice(address),
+ BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__GATT_CONNECT_JAVA,
+ connectionStatusToState(status),
+ app.appUid);
}
statsLogGattConnectionStateChange(
BluetoothProfile.GATT, address, clientIf, connectionState, status);
@@ -1379,6 +1393,13 @@ public class GattService extends ProfileService {
if (app != null) {
app.callback.onClientConnectionState(status, clientIf, false, address);
+ MetricsLogger.getInstance()
+ .logBluetoothEvent(
+ getDevice(address),
+ BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__GATT_DISCONNECT_JAVA,
+ BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__SUCCESS,
+ app.appUid);
}
statsLogGattConnectionStateChange(
BluetoothProfile.GATT,
@@ -1930,7 +1951,6 @@ public class GattService extends ProfileService {
for (Map.Entry<Integer, String> entry : connMap.entrySet()) {
Log.d(TAG, "disconnecting addr:" + entry.getValue());
clientDisconnect(entry.getKey(), entry.getValue(), attributionSource);
- // clientDisconnect(int clientIf, String address)
}
}
@@ -1967,7 +1987,8 @@ public class GattService extends ProfileService {
return;
}
if (parameters.getOwnAddressType() != AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
- || serverIf != 0) {
+ || serverIf != 0
+ || parameters.isDirected()) {
this.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
}
mAdvertiseManager.startAdvertisingSet(
@@ -2040,7 +2061,12 @@ public class GattService extends ProfileService {
mAdvertiseManager.setScanResponseData(advertiserId, data);
}
- @RequiresPermission(BLUETOOTH_ADVERTISE)
+ @RequiresPermission(
+ allOf = {
+ BLUETOOTH_ADVERTISE,
+ BLUETOOTH_PRIVILEGED,
+ },
+ conditional = true)
void setAdvertisingParameters(
int advertiserId,
AdvertisingSetParameters parameters,
@@ -2049,6 +2075,10 @@ public class GattService extends ProfileService {
this, attributionSource, "GattService setAdvertisingParameters")) {
return;
}
+ if (parameters.getOwnAddressType() != AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
+ || parameters.isDirected()) {
+ this.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ }
mAdvertiseManager.setAdvertisingParameters(advertiserId, parameters);
}
@@ -2156,6 +2186,15 @@ public class GattService extends ProfileService {
}
Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
+ for (ContextMap.Connection conn : mClientMap.getConnectionByApp(clientIf)) {
+ MetricsLogger.getInstance()
+ .logBluetoothEvent(
+ getDevice(conn.address),
+ BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__GATT_DISCONNECT_JAVA,
+ BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__END,
+ attributionSource.getUid());
+ }
mClientMap.remove(clientIf);
mNativeInterface.gattClientUnregisterApp(clientIf);
}
@@ -2198,6 +2237,18 @@ public class GattService extends ProfileService {
BluetoothProtoEnums.CONNECTION_STATE_CONNECTING,
-1);
+ MetricsLogger.getInstance()
+ .logBluetoothEvent(
+ getDevice(address),
+ BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__GATT_CONNECT_JAVA,
+ isDirect
+ ? BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__DIRECT_CONNECT
+ : BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__INDIRECT_CONNECT,
+ attributionSource.getUid());
+
int preferredMtu = 0;
// Some applications expect MTU to be exchanged immediately on connections
@@ -2248,6 +2299,13 @@ public class GattService extends ProfileService {
clientIf,
BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING,
-1);
+ MetricsLogger.getInstance()
+ .logBluetoothEvent(
+ getDevice(address),
+ BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__GATT_DISCONNECT_JAVA,
+ BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__START,
+ attributionSource.getUid());
mNativeInterface.gattClientDisconnect(clientIf, address, connId != null ? connId : 0);
}
@@ -2808,14 +2866,7 @@ public class GattService extends ProfileService {
maxConnectionEventLen);
}
- @RequiresPermission(BLUETOOTH_CONNECT)
- void subrateModeRequest(
- int clientIf, String address, int subrateMode, AttributionSource attributionSource) {
- if (!Utils.checkConnectPermissionForDataDelivery(
- this, attributionSource, "GattService subrateModeRequest")) {
- return;
- }
-
+ private int subrateModeRequest(int clientIf, BluetoothDevice device, int subrateMode) {
int subrateMin;
int subrateMax;
int maxLatency;
@@ -2851,64 +2902,15 @@ public class GattService extends ProfileService {
Log.d(
TAG,
- "subrateModeRequest() - "
- + "address="
- + BluetoothUtils.toAnonymizedAddress(address)
- + ", subrate min/max="
- + subrateMin
- + "/"
- + subrateMax
- + ", maxLatency="
- + maxLatency
- + ", continuation Number="
- + contNumber
- + ", timeout="
- + supervisionTimeout);
-
- mNativeInterface.gattSubrateRequest(
- clientIf,
- address,
- subrateMin,
- subrateMax,
- maxLatency,
- contNumber,
- supervisionTimeout);
- }
-
- @RequiresPermission(BLUETOOTH_CONNECT)
- void leSubrateRequest(
- int clientIf,
- String address,
- int subrateMin,
- int subrateMax,
- int maxLatency,
- int contNumber,
- int supervisionTimeout,
- AttributionSource attributionSource) {
- if (!Utils.checkConnectPermissionForDataDelivery(
- this, attributionSource, "GattService leSubrateRequest")) {
- return;
- }
-
- Log.d(
- TAG,
- "leSubrateRequest() - "
- + "address="
- + BluetoothUtils.toAnonymizedAddress(address)
- + ", subrate min/max="
- + subrateMin
- + "/"
- + subrateMax
- + ", maxLatency="
- + maxLatency
- + ", continuation Number="
- + contNumber
- + ", timeout="
- + supervisionTimeout);
+ ("subrateModeRequest(" + device + ", " + subrateMode + "): ")
+ + (", subrate min/max=" + subrateMin + "/" + subrateMax)
+ + (", maxLatency=" + maxLatency)
+ + (", continuationNumber=" + contNumber)
+ + (", timeout=" + supervisionTimeout));
- mNativeInterface.gattSubrateRequest(
+ return mNativeInterface.gattSubrateRequest(
clientIf,
- address,
+ device.getAddress(),
subrateMin,
subrateMax,
maxLatency,
@@ -3797,6 +3799,24 @@ public class GattService extends ProfileService {
mTransitionalScanHelper.dumpProto(builder);
}
+ private BluetoothDevice getDevice(String address) {
+ byte[] addressBytes = Utils.getBytesFromAddress(address);
+ return mAdapterService.getDeviceFromByte(addressBytes);
+ }
+
+ private static int connectionStatusToState(int status) {
+ return switch (status) {
+ // GATT_SUCCESS
+ case 0x00 -> BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__SUCCESS;
+ // GATT_CONNECTION_TIMEOUT
+ case 0x93 ->
+ BluetoothStatsLog
+ .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__CONNECTION_TIMEOUT;
+ // For now all other errors are bucketed together.
+ default -> BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__FAIL;
+ };
+ }
+
/**************************************************************************
* GATT Test functions
*************************************************************************/
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
index 2b0ee77e61..69feb368ef 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -1415,6 +1415,7 @@ public class HeadsetService extends ProfileService {
}
// Make sure the Audio Manager knows the previous active device is no longer active.
+ BluetoothDevice previousActiveDevice = mActiveDevice;
mActiveDevice = null;
mNativeInterface.setActiveDevice(null);
if (Utils.isScoManagedByAudioEnabled()) {
@@ -1422,7 +1423,7 @@ public class HeadsetService extends ProfileService {
.getAudioManager()
.handleBluetoothActiveDeviceChanged(
null,
- mActiveDevice,
+ previousActiveDevice,
BluetoothProfileConnectionInfo.createHfpInfo());
} else {
broadcastActiveDevice(null);
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index fa010889ef..123cf5eb7a 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -649,8 +649,6 @@ public class HeadsetClientStateMachine extends StateMachine {
action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1;
} else if (getCall(HfpClientCall.CALL_STATE_ACTIVE) != null) {
action = HeadsetClientHalConstants.CALL_ACTION_CHLD_3;
- } else if (flag == BluetoothHeadsetClient.CALL_ACCEPT_NONE) {
- action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
} else {
action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
}
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 dba7542953..4db0c1d5ac 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -26,6 +26,7 @@ import static com.android.bluetooth.flags.Flags.leaudioAllowedContextMask;
import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiManagePrimaryGroup;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeripheralEntrustment;
+import static com.android.bluetooth.flags.Flags.leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator;
import static com.android.bluetooth.flags.Flags.leaudioUseAudioModeListener;
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
@@ -51,7 +52,6 @@ import android.bluetooth.IBluetoothLeBroadcastCallback;
import android.bluetooth.IBluetoothVolumeControl;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.IScannerCallback;
-import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
@@ -222,10 +222,8 @@ public class LeAudioService extends ProfileService {
new RemoteCallbackList<>();
BluetoothLeScanner mAudioServersScanner;
- /* When mScanCallback is not null, it means scan is started. */
- ScanCallback mScanCallback;
- private final AudioServerScanCallback2 mScanCallback2 = new AudioServerScanCallback2();
+ private final AudioServerScanCallback mScanCallback = new AudioServerScanCallback();
public LeAudioService(Context ctx) {
this(ctx, LeAudioNativeInterface.getInstance());
@@ -604,30 +602,6 @@ public class LeAudioService extends ProfileService {
// Setup codec config
mLeAudioCodecConfig = new LeAudioCodecConfig(this);
- if (!Flags.leaudioSynchronizeStart()) {
- // Delay the call to init by posting it. This ensures TBS and MCS are fully initialized
- // before we start accepting connections
- mHandler.post(this::init);
- return;
- }
- mNativeInterface.init(mLeAudioCodecConfig.getCodecConfigOffloading());
-
- if (leaudioUseAudioModeListener()) {
- mAudioManager.addOnModeChangedListener(getMainExecutor(), mAudioModeChangeListener);
- }
- }
-
- // TODO: b/341385684 -- Delete the init method as it has been inlined in start
- private void init() {
- if (!isAvailable()) {
- Log.e(TAG, " Service disabled before init");
- return;
- }
-
- if (!mTmapStarted) {
- mTmapStarted = registerTmap();
- }
-
mNativeInterface.init(mLeAudioCodecConfig.getCodecConfigOffloading());
if (leaudioUseAudioModeListener()) {
@@ -656,9 +630,6 @@ public class LeAudioService extends ProfileService {
clearCreateBroadcastTimeoutCallback();
- if (!Flags.leaudioSynchronizeStart()) {
- mHandler.removeCallbacks(this::init);
- }
removeActiveDevice(false);
if (mTmapGattServer == null) {
@@ -669,7 +640,7 @@ public class LeAudioService extends ProfileService {
mTmapStarted = false;
}
- stopAudioServersBackgroundScan();
+ mScanCallback.stopBackgroundScan();
mAudioServersScanner = null;
// Don't wait for async call with INACTIVE group status, clean active
@@ -1600,7 +1571,13 @@ public class LeAudioService extends ProfileService {
return false;
}
- return descriptor.mGroupId == mUnicastGroupIdDeactivatedForBroadcastTransition;
+ if (leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()) {
+ return (descriptor.mGroupId == mUnicastGroupIdDeactivatedForBroadcastTransition)
+ || device.equals(mActiveAudioInDevice)
+ || device.equals(mActiveAudioOutDevice);
+ } else {
+ return descriptor.mGroupId == mUnicastGroupIdDeactivatedForBroadcastTransition;
+ }
}
/** Return true if group is primary - is active or was active before switch to broadcast */
@@ -1984,7 +1961,7 @@ public class LeAudioService extends ProfileService {
return true;
}
- private class AudioServerScanCallback2 extends IScannerCallback.Stub {
+ private class AudioServerScanCallback extends IScannerCallback.Stub {
// See BluetoothLeScanner.BleScanCallbackWrapper.mScannerId
int mScannerId = 0;
@@ -2083,44 +2060,6 @@ public class LeAudioService extends ProfileService {
public void onScanManagerErrorCallback(int errorCode) {}
}
- private class AudioServerScanCallback extends ScanCallback {
- int mMaxScanRetries = 10;
- int mScanRetries = 0;
-
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- /* Filter is set in the way, that there will be no results found.
- * We just need a scanner to be running for the APCF filtering defined in native
- */
- }
-
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- /* Filter is set in the way, that there will be no results found.
- * We just need a scanner to be running for the APCF filtering defined in native
- */
- }
-
- @Override
- public void onScanFailed(int errorCode) {
- Log.w(TAG, "Scan failed err: " + errorCode + " scan retries: " + mScanRetries);
- switch (errorCode) {
- case SCAN_FAILED_INTERNAL_ERROR:
- case SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
- if (mScanRetries < mMaxScanRetries) {
- mScanRetries++;
- Log.w(TAG, "Failed to start. Let's retry");
- mHandler.post(() -> startAudioServersBackgroundScan(/* retry= */ true));
- }
- break;
- default:
- /* Indicate scan is no running */
- mScanCallback = null;
- break;
- }
- }
- }
-
@VisibleForTesting
boolean handleAudioDeviceAdded(
BluetoothDevice device, int type, boolean isSink, boolean isSource) {
@@ -2968,7 +2907,7 @@ public class LeAudioService extends ProfileService {
.getBroadcastItem(i)
.onGroupStreamStatusChanged(groupId, groupStreamStatus);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mLeAudioCallbacks.finishBroadcast();
@@ -2984,7 +2923,7 @@ public class LeAudioService extends ProfileService {
.getBroadcastItem(i)
.onBroadcastToUnicastFallbackGroupChanged(groupId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mLeAudioCallbacks.finishBroadcast();
@@ -3129,87 +3068,6 @@ public class LeAudioService extends ProfileService {
}
}
- @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/348562830 - Remove with flag
- void stopAudioServersBackgroundScan() {
- Log.d(TAG, "stopAudioServersBackgroundScan");
-
- if (Flags.leaudioCallStartScanDirectly()) {
- mScanCallback2.stopBackgroundScan();
- return;
- }
-
- if (mAudioServersScanner == null || mScanCallback == null) {
- Log.d(TAG, "stopAudioServersBackgroundScan: already stopped");
- return;
- }
-
- try {
- mAudioServersScanner.stopScan(mScanCallback);
- } catch (IllegalStateException e) {
- Log.e(TAG, "Fail to stop scanner, consider it stopped", e);
- }
-
- /* Callback is the indicator for scanning being enabled */
- mScanCallback = null;
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/348562830 - Remove with flag
- void startAudioServersBackgroundScan(boolean retry) {
- Log.d(TAG, "startAudioServersBackgroundScan, retry: " + retry);
-
- if (!isScannerNeeded()) {
- return;
- }
-
- if (Flags.leaudioCallStartScanDirectly()) {
- mScanCallback2.startBackgroundScan();
- return;
- }
-
- if (mAudioServersScanner == null) {
- mAudioServersScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
- if (mAudioServersScanner == null) {
- Log.e(TAG, "startAudioServersBackgroundScan: Could not get scanner");
- return;
- }
- }
-
- if (!retry) {
- if (mScanCallback != null) {
- Log.d(TAG, "startAudioServersBackgroundScan: Scanning already enabled");
- return;
- }
- mScanCallback = new AudioServerScanCallback();
- }
-
- /* Filter we are building here will not match to anything.
- * Eventually we should be able to start scan from native when
- * b/276350722 is done
- */
- byte[] serviceData = new byte[] {0x11};
-
- ArrayList filterList = new ArrayList<ScanFilter>();
- ScanFilter filter =
- new ScanFilter.Builder()
- .setServiceData(BluetoothUuid.LE_AUDIO, serviceData)
- .build();
- filterList.add(filter);
-
- ScanSettings settings =
- new ScanSettings.Builder()
- .setLegacy(false)
- .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
- .setPhy(BluetoothDevice.PHY_LE_1M)
- .build();
-
- try {
- mAudioServersScanner.startScan(filterList, settings, mScanCallback);
- } catch (IllegalStateException e) {
- Log.e(TAG, "Fail to start scanner, consider it stopped", e);
- mScanCallback = null;
- }
- }
-
void transitionFromBroadcastToUnicast() {
if (mUnicastGroupIdDeactivatedForBroadcastTransition == LE_AUDIO_GROUP_ID_INVALID) {
Log.d(TAG, "No deactivated group due for broadcast transmission");
@@ -3439,7 +3297,10 @@ public class LeAudioService extends ProfileService {
case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTING:
case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTED:
deviceDescriptor.mAclConnected = false;
- startAudioServersBackgroundScan(/* retry= */ false);
+
+ if (isScannerNeeded()) {
+ mScanCallback.startBackgroundScan();
+ }
boolean disconnectDueToUnbond =
(BluetoothDevice.BOND_NONE
@@ -4171,7 +4032,7 @@ public class LeAudioService extends ProfileService {
}
mDeviceDescriptors.remove(device);
if (!isScannerNeeded()) {
- stopAudioServersBackgroundScan();
+ mScanCallback.stopBackgroundScan();
}
} finally {
mGroupWriteLock.unlock();
@@ -4213,7 +4074,7 @@ public class LeAudioService extends ProfileService {
}
if (!isScannerNeeded()) {
- stopAudioServersBackgroundScan();
+ mScanCallback.stopBackgroundScan();
}
/* Set by default earliest connected device */
@@ -4249,7 +4110,7 @@ public class LeAudioService extends ProfileService {
}
if (!isScannerNeeded()) {
- stopAudioServersBackgroundScan();
+ mScanCallback.stopBackgroundScan();
}
mGroupReadLock.lock();
@@ -4782,7 +4643,9 @@ public class LeAudioService extends ProfileService {
mGroupReadLock.unlock();
}
- startAudioServersBackgroundScan(/* retry= */ false);
+ if (isScannerNeeded()) {
+ mScanCallback.startBackgroundScan();
+ }
}
@VisibleForTesting
@@ -4894,7 +4757,9 @@ public class LeAudioService extends ProfileService {
if (mBluetoothEnabled) {
setAuthorizationForRelatedProfiles(device, true);
- startAudioServersBackgroundScan(/* retry= */ false);
+ if (isScannerNeeded()) {
+ mScanCallback.startBackgroundScan();
+ }
}
}
@@ -4910,7 +4775,7 @@ public class LeAudioService extends ProfileService {
try {
mLeAudioCallbacks.getBroadcastItem(i).onGroupNodeAdded(device, groupId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mLeAudioCallbacks.finishBroadcast();
@@ -4989,7 +4854,7 @@ public class LeAudioService extends ProfileService {
try {
mLeAudioCallbacks.getBroadcastItem(i).onGroupNodeRemoved(device, groupId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mLeAudioCallbacks.finishBroadcast();
@@ -5003,7 +4868,7 @@ public class LeAudioService extends ProfileService {
try {
mLeAudioCallbacks.getBroadcastItem(i).onGroupStatusChanged(groupId, status);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mLeAudioCallbacks.finishBroadcast();
@@ -5017,7 +4882,7 @@ public class LeAudioService extends ProfileService {
try {
mLeAudioCallbacks.getBroadcastItem(i).onCodecConfigChanged(groupId, status);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mLeAudioCallbacks.finishBroadcast();
@@ -5031,7 +4896,7 @@ public class LeAudioService extends ProfileService {
try {
mBroadcastCallbacks.getBroadcastItem(i).onBroadcastStarted(reason, broadcastId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5045,7 +4910,7 @@ public class LeAudioService extends ProfileService {
try {
mBroadcastCallbacks.getBroadcastItem(i).onBroadcastStartFailed(reason);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5059,7 +4924,7 @@ public class LeAudioService extends ProfileService {
try {
mBroadcastCallbacks.getBroadcastItem(i).onBroadcastStopped(reason, broadcastId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5073,7 +4938,7 @@ public class LeAudioService extends ProfileService {
try {
mBroadcastCallbacks.getBroadcastItem(i).onBroadcastStopFailed(reason);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5087,7 +4952,7 @@ public class LeAudioService extends ProfileService {
try {
mBroadcastCallbacks.getBroadcastItem(i).onPlaybackStarted(reason, broadcastId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5101,7 +4966,7 @@ public class LeAudioService extends ProfileService {
try {
mBroadcastCallbacks.getBroadcastItem(i).onPlaybackStopped(reason, broadcastId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5117,7 +4982,7 @@ public class LeAudioService extends ProfileService {
.getBroadcastItem(i)
.onBroadcastUpdateFailed(reason, broadcastId);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
@@ -5134,7 +4999,7 @@ public class LeAudioService extends ProfileService {
.getBroadcastItem(i)
.onBroadcastMetadataChanged(broadcastId, metadata);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mBroadcastCallbacks.finishBroadcast();
diff --git a/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java b/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java
index 657ea4d5a9..3223c7764e 100644
--- a/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java
+++ b/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java
@@ -20,16 +20,18 @@ import android.bluetooth.le.ScanFilter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Objects;
import java.util.UUID;
/** Helper class used to manage MSFT Advertisement Monitors. */
class MsftAdvMonitor {
- /* Only pattern filtering is supported currently */
+ /* Only pattern and address filtering are supported currently */
// private static final int MSFT_CONDITION_TYPE_ALL = 0x00;
private static final int MSFT_CONDITION_TYPE_PATTERNS = 0x01;
// private static final int MSFT_CONDITION_TYPE_UUID = 0x02;
// private static final int MSFT_CONDITION_TYPE_IRK = 0x03;
- // private static final int MSFT_CONDITION_TYPE_ADDRESS = 0x04;
+ private static final int MSFT_CONDITION_TYPE_ADDRESS = 0x04;
// Hardcoded values taken from CrOS defaults
private static final byte RSSI_THRESHOLD_HIGH = (byte) 0xBF; // 191
@@ -50,6 +52,25 @@ class MsftAdvMonitor {
public byte ad_type;
public byte start_byte;
public byte[] pattern;
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof Pattern other)) {
+ return false;
+ }
+
+ return other.ad_type == this.ad_type
+ && other.start_byte == this.start_byte
+ && Arrays.equals(other.pattern, this.pattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ad_type, start_byte, Arrays.hashCode(pattern));
+ }
}
static class Address {
@@ -70,6 +91,13 @@ class MsftAdvMonitor {
mMonitor.rssi_sampling_period = RSSI_SAMPLING_PERIOD;
mMonitor.condition_type = MSFT_CONDITION_TYPE_PATTERNS;
+ if (filter.getDeviceAddress() != null) {
+ mMonitor.condition_type = MSFT_CONDITION_TYPE_ADDRESS;
+ mAddress.addr_type = (byte) filter.getAddressType();
+ mAddress.bd_addr = filter.getDeviceAddress();
+ return;
+ }
+
if (filter.getServiceDataUuid() != null && dataMaskIsEmpty(filter.getServiceDataMask())) {
Pattern pattern = new Pattern();
pattern.ad_type = (byte) 0x16; // Bluetooth Core Spec Part A, Section 1
@@ -93,11 +121,6 @@ class MsftAdvMonitor {
pattern.pattern = filter.getAdvertisingData();
mPatterns.add(pattern);
}
-
- if (filter.getDeviceAddress() != null) {
- mAddress.addr_type = (byte) filter.getAddressType();
- mAddress.bd_addr = filter.getDeviceAddress();
- }
}
Monitor getMonitor() {
diff --git a/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternList.java b/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternList.java
new file mode 100644
index 0000000000..922c898477
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternList.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.le_scan;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Helper class to keep track of MSFT patterns, their filter index, and number of monitors
+ * registered with that pattern. Some chipsets don't support multiple monitors with the same
+ * pattern. To solve that and to generally ease their task, we merge monitors with the same pattern,
+ * so those monitors will only be sent once.
+ */
+class MsftAdvMonitorMergedPatternList {
+ static class MsftAdvMonitorMergedPattern {
+ private final MsftAdvMonitor.Pattern[] mPatterns;
+ private final int mFilterIndex;
+ private int mCount = 0;
+
+ MsftAdvMonitorMergedPattern(MsftAdvMonitor.Pattern[] pattern, int filterIndex) {
+ mPatterns = pattern;
+ mFilterIndex = filterIndex;
+ }
+ }
+
+ List<MsftAdvMonitorMergedPattern> mMergedPatterns = new ArrayList<>();
+
+ // Two patterns are considered equal if they have the exact same pattern
+ // in the same order. Therefore A+B and B+A are considered different, as
+ // well as A and A+A. This shouldn't causes issues but could be optimized.
+ // Returns merged pattern or null if not found.
+ private MsftAdvMonitorMergedPattern getMergedPattern(MsftAdvMonitor.Pattern[] pattern) {
+ return mMergedPatterns.stream()
+ .filter(mergedPattern -> Arrays.equals(mergedPattern.mPatterns, pattern))
+ .findFirst()
+ .orElse(null);
+ }
+
+ // If pattern doesn't exist, creates new entry with given index.
+ // If pattern exists, increases count and returns filter index.
+ int add(int filterIndex, MsftAdvMonitor.Pattern[] pattern) {
+ MsftAdvMonitorMergedPattern mergedPattern = (getMergedPattern(pattern));
+ if (mergedPattern == null) {
+ mergedPattern = new MsftAdvMonitorMergedPattern(pattern, filterIndex);
+ mMergedPatterns.add(mergedPattern);
+ }
+
+ mergedPattern.mCount++;
+ return mergedPattern.mFilterIndex;
+ }
+
+ // If pattern exists, decreases count. If count is 0, removes entry.
+ // Returns true if there are no more instances of the given filter index
+ boolean remove(int filterIndex) {
+ mMergedPatterns.stream()
+ .filter(pattern -> pattern.mFilterIndex == filterIndex)
+ .forEach(pattern -> pattern.mCount--);
+ return mMergedPatterns.removeIf(pattern -> pattern.mCount == 0);
+ }
+}
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 36beda6793..d5e97a73bc 100644
--- a/android/app/src/com/android/bluetooth/le_scan/ScanController.java
+++ b/android/app/src/com/android/bluetooth/le_scan/ScanController.java
@@ -46,6 +46,7 @@ public class ScanController {
private static final String TAG = ScanController.class.getSimpleName();
public final TransitionalScanHelper mTransitionalScanHelper;
+ public final HandlerThread mScanThread;
private final BluetoothScanBinder mBinder;
@@ -72,15 +73,16 @@ public class ScanController {
mMainLooper = adapterService.getMainLooper();
mBinder = new BluetoothScanBinder(this);
mIsAvailable = true;
- HandlerThread thread = new HandlerThread("BluetoothScanManager");
- thread.start();
- mTransitionalScanHelper.start(thread.getLooper());
+ mScanThread = new HandlerThread("BluetoothScanManager");
+ mScanThread.start();
+ mTransitionalScanHelper.start(mScanThread.getLooper());
}
public void stop() {
Log.d(TAG, "stop()");
mIsAvailable = false;
mBinder.clearScanController();
+ mScanThread.quitSafely();
mTransitionalScanHelper.stop();
mTransitionalScanHelper.cleanup();
}
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 014645601a..453b5849fd 100644
--- a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java
+++ b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java
@@ -119,7 +119,6 @@ public class ScanManager {
@GuardedBy("mCurUsedTrackableAdvertisementsLock")
private int mCurUsedTrackableAdvertisements = 0;
- private final Context mContext;
private final TransitionalScanHelper mScanHelper;
private final AdapterService mAdapterService;
private final TimeProvider mTimeProvider;
@@ -170,13 +169,12 @@ public class ScanManager {
mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
mSuspendedScanClients =
Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
- mContext = adapterService;
mScanHelper = scanHelper;
mAdapterService = adapterService;
mTimeProvider = timeProvider;
mScanNative = new ScanNative(scanHelper);
- mDisplayManager = mContext.getSystemService(DisplayManager.class);
- mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mDisplayManager = mAdapterService.getSystemService(DisplayManager.class);
+ mActivityManager = mAdapterService.getSystemService(ActivityManager.class);
mLocationManager = mAdapterService.getSystemService(LocationManager.class);
mBluetoothAdapterProxy = bluetoothAdapterProxy;
mIsConnecting = false;
@@ -203,7 +201,7 @@ public class ScanManager {
}
IntentFilter locationIntentFilter = new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
locationIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(mLocationReceiver, locationIntentFilter);
+ mAdapterService.registerReceiver(mLocationReceiver, locationIntentFilter);
}
public void cleanup() {
@@ -226,13 +224,9 @@ public class ScanManager {
// Shut down the thread
mHandler.removeCallbacksAndMessages(null);
- Looper looper = mHandler.getLooper();
- if (looper != null) {
- looper.quitSafely();
- }
try {
- mContext.unregisterReceiver(mLocationReceiver);
+ mAdapterService.unregisterReceiver(mLocationReceiver);
} catch (IllegalArgumentException e) {
Log.w(TAG, "exception when invoking unregisterReceiver(mLocationReceiver)", e);
}
@@ -725,14 +719,9 @@ public class ScanManager {
return;
}
int importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
- if (Flags.leScanUseUidForImportance()) {
- for (String packageName : packages) {
- importance =
- Math.min(
- importance, mActivityManager.getPackageImportance(packageName));
- }
- } else {
- importance = mActivityManager.getPackageImportance(packages[0]);
+ for (String packageName : packages) {
+ importance =
+ Math.min(importance, mActivityManager.getPackageImportance(packageName));
}
boolean isForeground =
importance
@@ -1017,6 +1006,9 @@ public class ScanManager {
private final boolean mIsMsftSupported;
// Whether or not MSFT-based scanning is currently enabled in the controller
private boolean scanEnabledMsft = false;
+ // List of merged MSFT patterns
+ private final MsftAdvMonitorMergedPatternList mMsftAdvMonitorMergedPatternList =
+ new MsftAdvMonitorMergedPatternList();
ScanNative(TransitionalScanHelper scanHelper) {
mNativeInterface = ScanObjectsFactory.getInstance().getScanNativeInterface();
@@ -1024,11 +1016,11 @@ public class ScanManager {
mFilterIndexStack = new ArrayDeque<Integer>();
mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>();
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mAlarmManager = mAdapterService.getSystemService(AlarmManager.class);
Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
mBatchScanIntervalIntent =
PendingIntent.getBroadcast(
- mContext, 0, batchIntent, PendingIntent.FLAG_IMMUTABLE);
+ mAdapterService, 0, batchIntent, PendingIntent.FLAG_IMMUTABLE);
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
@@ -1050,7 +1042,7 @@ public class ScanManager {
}
}
});
- mContext.registerReceiver(mBatchAlarmReceiver.get(), filter);
+ mAdapterService.registerReceiver(mBatchAlarmReceiver.get(), filter);
mIsMsftSupported =
Flags.leScanMsftSupport()
@@ -1323,7 +1315,7 @@ public class ScanManager {
// infrequently anyway. To avoid redefining parameter sets, map to the low duty cycle
// parameter set as follows.
private int getBatchScanWindowMillis(int scanMode) {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = mAdapterService.getContentResolver();
switch (scanMode) {
case ScanSettings.SCAN_MODE_LOW_LATENCY:
return Settings.Global.getInt(
@@ -1341,7 +1333,7 @@ public class ScanManager {
}
private int getBatchScanIntervalMillis(int scanMode) {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = mAdapterService.getContentResolver();
switch (scanMode) {
case ScanSettings.SCAN_MODE_LOW_LATENCY:
return Settings.Global.getInt(
@@ -1521,7 +1513,7 @@ public class ScanManager {
// Protect against multiple calls of cleanup.
BroadcastReceiver receiver = mBatchAlarmReceiver.getAndSet(null);
if (receiver != null) {
- mContext.unregisterReceiver(receiver);
+ mAdapterService.unregisterReceiver(receiver);
}
mNativeInterface.cleanup();
}
@@ -1781,7 +1773,7 @@ public class ScanManager {
}
private int getScanWindowMillis(ScanSettings settings) {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = mAdapterService.getContentResolver();
if (settings == null) {
return Settings.Global.getInt(
resolver,
@@ -1819,7 +1811,7 @@ public class ScanManager {
}
private int getScanIntervalMillis(ScanSettings settings) {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = mAdapterService.getContentResolver();
if (settings == null) {
return Settings.Global.getInt(
resolver,
@@ -1987,18 +1979,48 @@ public class ScanManager {
Deque<Integer> clientFilterIndices = new ArrayDeque<>();
for (ScanFilter filter : client.filters) {
- int filterIndex = mFilterIndexStack.pop();
MsftAdvMonitor monitor = new MsftAdvMonitor(filter);
- resetCountDownLatch();
- mNativeInterface.gattClientMsftAdvMonitorAdd(
- monitor.getMonitor(),
- monitor.getPatterns(),
- monitor.getAddress(),
- filterIndex);
- waitForCallback();
+ if (monitor.getAddress().bd_addr != null) {
+ int filterIndex = mFilterIndexStack.pop();
+
+ resetCountDownLatch();
+ mNativeInterface.gattClientMsftAdvMonitorAdd(
+ monitor.getMonitor(),
+ monitor.getPatterns(),
+ monitor.getAddress(),
+ filterIndex);
+ waitForCallback();
+
+ clientFilterIndices.add(filterIndex);
+ }
- clientFilterIndices.add(filterIndex);
+ if (monitor.getPatterns().length == 0) {
+ Log.d(
+ TAG,
+ "No MSFT pattern or address was translated from client filter: "
+ + filter);
+ continue;
+ }
+
+ // Some chipsets don't support multiple monitors with the same pattern. Skip
+ // creating a new monitor if the pattern has alreaady been registered
+ int filterIndex = mFilterIndexStack.pop();
+ int existingFilterIndex =
+ mMsftAdvMonitorMergedPatternList.add(filterIndex, monitor.getPatterns());
+ if (filterIndex == existingFilterIndex) {
+ resetCountDownLatch();
+ mNativeInterface.gattClientMsftAdvMonitorAdd(
+ monitor.getMonitor(),
+ monitor.getPatterns(),
+ monitor.getAddress(),
+ filterIndex);
+ waitForCallback();
+ } else {
+ mFilterIndexStack.add(filterIndex);
+ }
+
+ clientFilterIndices.add(existingFilterIndex);
}
mClientFilterIndexMap.put(client.scannerId, clientFilterIndices);
@@ -2008,11 +2030,13 @@ public class ScanManager {
private void removeFiltersMsft(ScanClient client) {
Deque<Integer> clientFilterIndices = mClientFilterIndexMap.remove(client.scannerId);
if (clientFilterIndices != null) {
- mFilterIndexStack.addAll(clientFilterIndices);
for (int filterIndex : clientFilterIndices) {
- resetCountDownLatch();
- mNativeInterface.gattClientMsftAdvMonitorRemove(filterIndex);
- waitForCallback();
+ if (mMsftAdvMonitorMergedPatternList.remove(filterIndex)) {
+ resetCountDownLatch();
+ mNativeInterface.gattClientMsftAdvMonitorRemove(filterIndex);
+ waitForCallback();
+ mFilterIndexStack.add(filterIndex);
+ }
}
}
diff --git a/android/app/src/com/android/bluetooth/le_scan/ScanObjectsFactory.java b/android/app/src/com/android/bluetooth/le_scan/ScanObjectsFactory.java
index 641c5f9bb2..f3fba49c79 100644
--- a/android/app/src/com/android/bluetooth/le_scan/ScanObjectsFactory.java
+++ b/android/app/src/com/android/bluetooth/le_scan/ScanObjectsFactory.java
@@ -16,7 +16,7 @@
package com.android.bluetooth.le_scan;
-import static com.android.bluetooth.Utils.sSystemClock;
+import static com.android.bluetooth.Utils.getSystemClock;
import android.os.Looper;
import android.util.Log;
@@ -79,7 +79,7 @@ public class ScanObjectsFactory {
BluetoothAdapterProxy bluetoothAdapterProxy,
Looper looper) {
return new ScanManager(
- adapterService, scanHelper, bluetoothAdapterProxy, looper, sSystemClock);
+ adapterService, scanHelper, bluetoothAdapterProxy, looper, getSystemClock());
}
public PeriodicScanManager createPeriodicScanManager(AdapterService adapterService) {
diff --git a/android/app/src/com/android/bluetooth/le_scan/ScannerMap.java b/android/app/src/com/android/bluetooth/le_scan/ScannerMap.java
index a88630a571..00d9641032 100644
--- a/android/app/src/com/android/bluetooth/le_scan/ScannerMap.java
+++ b/android/app/src/com/android/bluetooth/le_scan/ScannerMap.java
@@ -15,7 +15,7 @@
*/
package com.android.bluetooth.le_scan;
-import static com.android.bluetooth.Utils.sSystemClock;
+import static com.android.bluetooth.Utils.getSystemClock;
import static com.android.bluetooth.util.AttributionSourceUtil.getLastAttributionTag;
import android.annotation.Nullable;
@@ -95,7 +95,12 @@ public class ScannerMap {
if (appScanStats == null) {
appScanStats =
new AppScanStats(
- appName, workSource, this, adapterService, scanHelper, sSystemClock);
+ appName,
+ workSource,
+ this,
+ adapterService,
+ scanHelper,
+ getSystemClock());
mAppScanStatsMap.put(appUid, appScanStats);
}
ScannerApp app =
diff --git a/android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java b/android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java
index c68bf2d249..102d0d0649 100644
--- a/android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java
+++ b/android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java
@@ -60,7 +60,6 @@ import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
-import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.gatt.GattServiceConfig;
import com.android.bluetooth.util.NumberUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -962,16 +961,10 @@ public class TransitionalScanHelper {
return;
}
- BluetoothDevice device;
- if (Flags.leScanUseAddressType()) {
- device =
- BluetoothAdapter.getDefaultAdapter()
- .getRemoteLeDevice(
- trackingInfo.getAddress(), trackingInfo.getAddressType());
- } else {
- device =
- BluetoothAdapter.getDefaultAdapter().getRemoteDevice(trackingInfo.getAddress());
- }
+ BluetoothDevice device =
+ BluetoothAdapter.getDefaultAdapter()
+ .getRemoteLeDevice(
+ trackingInfo.getAddress(), trackingInfo.getAddressType());
int advertiserState = trackingInfo.getAdvState();
ScanResult result =
new ScanResult(
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapContent.java b/android/app/src/com/android/bluetooth/map/BluetoothMapContent.java
index b32ba797b2..2cb5b3f014 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapContent.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapContent.java
@@ -3483,8 +3483,6 @@ public class BluetoothMapContent {
BluetoothProtoEnums.BLUETOOTH_MAP_CONTENT,
BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION,
4);
- // skip this id
- continue;
}
}
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
index e0fce72338..5facd76fcc 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
@@ -57,7 +57,6 @@ import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.Utils;
import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils;
-import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
import com.android.bluetooth.map.BluetoothMapbMessageMime.MimePart;
import com.android.bluetooth.mapapi.BluetoothMapContract;
@@ -1558,19 +1557,12 @@ public class BluetoothMapContentObserver {
> BluetoothMapUtils.MAP_EVENT_REPORT_V10) {
long timestamp = c.getLong(c.getColumnIndex(Sms.DATE));
String date = BluetoothMapUtils.getDateTimeString(timestamp);
- if (Flags.mapLimitNotification()) {
- if (BluetoothMapUtils.isDateTimeOlderThanDuration(
- timestamp, NEW_MESSAGE_DURATION_FOR_NOTIFICATION)) {
- msgListSms.remove(id);
- continue;
- }
- } else {
- if (BluetoothMapUtils.isDateTimeOlderThanOneYear(timestamp)) {
- // Skip sending message events older than one year
- msgListSms.remove(id);
- continue;
- }
+ if (BluetoothMapUtils.isDateTimeOlderThanDuration(
+ timestamp, NEW_MESSAGE_DURATION_FOR_NOTIFICATION)) {
+ msgListSms.remove(id);
+ continue;
}
+
String subject = c.getString(c.getColumnIndex(Sms.BODY));
if (subject == null) {
subject = "";
@@ -1813,18 +1805,10 @@ public class BluetoothMapContentObserver {
TimeUnit.SECONDS.toMillis(
c.getLong(c.getColumnIndex(Mms.DATE)));
String date = BluetoothMapUtils.getDateTimeString(timestamp);
- if (Flags.mapLimitNotification()) {
- if (BluetoothMapUtils.isDateTimeOlderThanDuration(
- timestamp, NEW_MESSAGE_DURATION_FOR_NOTIFICATION)) {
- msgListMms.remove(id);
- continue;
- }
- } else {
- if (BluetoothMapUtils.isDateTimeOlderThanOneYear(timestamp)) {
- // Skip sending new message events older than one year
- msgListMms.remove(id);
- continue;
- }
+ if (BluetoothMapUtils.isDateTimeOlderThanDuration(
+ timestamp, NEW_MESSAGE_DURATION_FOR_NOTIFICATION)) {
+ msgListMms.remove(id);
+ continue;
}
String subject = c.getString(c.getColumnIndex(Mms.SUBJECT));
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapConvoListingElement.java b/android/app/src/com/android/bluetooth/map/BluetoothMapConvoListingElement.java
index f51a2f813e..9d29a77fc7 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapConvoListingElement.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapConvoListingElement.java
@@ -323,7 +323,6 @@ public class BluetoothMapConvoListingElement
} else {
Log.w(TAG, "Unknown XML tag: " + name);
Utils.skipCurrentTag(parser);
- continue;
}
}
// As we have extracted all attributes, we should expect an end-tag
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java b/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java
index 321fbe3b4f..6f5687dc36 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapUtils.java
@@ -578,59 +578,54 @@ public class BluetoothMapUtils {
* */
for (in = 0, out = 0; in < stopCnt; in++) {
byte b0 = input[in];
- if (b0 == '=') {
- byte b1 = input[++in];
- byte b2 = input[++in];
- if (b1 == '\r' && b2 == '\n') {
- continue; // soft line break, remove all tree;
+ if (b0 != '=') {
+ output[out++] = b0;
+ continue;
+ }
+ byte b1 = input[++in];
+ byte b2 = input[++in];
+ if (b1 == '\r' && b2 == '\n') {
+ continue; // soft line break, remove all tree;
+ }
+ if (((b1 >= '0' && b1 <= '9') || (b1 >= 'A' && b1 <= 'F') || (b1 >= 'a' && b1 <= 'f'))
+ && ((b2 >= '0' && b2 <= '9')
+ || (b2 >= 'A' && b2 <= 'F')
+ || (b2 >= 'a' && b2 <= 'f'))) {
+ Log.v(TAG, "Found hex number: " + formatSimple("%c%c", b1, b2));
+ if (b1 <= '9') {
+ b1 = (byte) (b1 - '0');
+ } else if (b1 <= 'F') {
+ b1 = (byte) (b1 - 'A' + 10);
+ } else if (b1 <= 'f') {
+ b1 = (byte) (b1 - 'a' + 10);
}
- if (((b1 >= '0' && b1 <= '9')
- || (b1 >= 'A' && b1 <= 'F')
- || (b1 >= 'a' && b1 <= 'f'))
- && ((b2 >= '0' && b2 <= '9')
- || (b2 >= 'A' && b2 <= 'F')
- || (b2 >= 'a' && b2 <= 'f'))) {
- Log.v(TAG, "Found hex number: " + formatSimple("%c%c", b1, b2));
- if (b1 <= '9') {
- b1 = (byte) (b1 - '0');
- } else if (b1 <= 'F') {
- b1 = (byte) (b1 - 'A' + 10);
- } else if (b1 <= 'f') {
- b1 = (byte) (b1 - 'a' + 10);
- }
- if (b2 <= '9') {
- b2 = (byte) (b2 - '0');
- } else if (b2 <= 'F') {
- b2 = (byte) (b2 - 'A' + 10);
- } else if (b2 <= 'f') {
- b2 = (byte) (b2 - 'a' + 10);
- }
+ if (b2 <= '9') {
+ b2 = (byte) (b2 - '0');
+ } else if (b2 <= 'F') {
+ b2 = (byte) (b2 - 'A' + 10);
+ } else if (b2 <= 'f') {
+ b2 = (byte) (b2 - 'a' + 10);
+ }
- Log.v(TAG, "Resulting nibble values: " + formatSimple("b1=%x b2=%x", b1, b2));
+ Log.v(TAG, "Resulting nibble values: " + formatSimple("b1=%x b2=%x", b1, b2));
- output[out++] = (byte) (b1 << 4 | b2); // valid hex char, append
- Log.v(TAG, "Resulting value: " + formatSimple("0x%2x", output[out - 1]));
- continue;
- }
- Log.w(
- TAG,
- "Received wrongly quoted printable encoded text. "
- + "Continuing at best effort...");
- ContentProfileErrorReportUtils.report(
- BluetoothProfile.MAP,
- BluetoothProtoEnums.BLUETOOTH_MAP_UTILS,
- BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN,
- 6);
- /* If we get a '=' without either a hex value or CRLF following, just add it and
- * rewind the in counter. */
- output[out++] = b0;
- in -= 2;
- continue;
- } else {
- output[out++] = b0;
+ output[out++] = (byte) (b1 << 4 | b2); // valid hex char, append
+ Log.v(TAG, "Resulting value: " + formatSimple("0x%2x", output[out - 1]));
continue;
}
+ Log.w(
+ TAG,
+ "Received wrongly quoted printable encoded text. Continuing at best effort...");
+ ContentProfileErrorReportUtils.report(
+ BluetoothProfile.MAP,
+ BluetoothProtoEnums.BLUETOOTH_MAP_UTILS,
+ BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN,
+ 6);
+ /* If we get a '=' without either a hex value or CRLF following, just add it and
+ * rewind the in counter. */
+ output[out++] = b0;
+ in -= 2;
}
// Just add any remaining characters. If they contain any encoding, it is invalid,
@@ -755,23 +750,6 @@ public class BluetoothMapUtils {
return format.format(cal.getTime());
}
- static boolean isDateTimeOlderThanOneYear(long timestamp) {
- Calendar cal = Calendar.getInstance();
- cal.setTimeInMillis(timestamp);
- Calendar oneYearAgo = Calendar.getInstance();
- oneYearAgo.add(Calendar.YEAR, -1);
- if (cal.before(oneYearAgo)) {
- Log.v(
- TAG,
- "isDateTimeOlderThanOneYear "
- + cal.getTimeInMillis()
- + " oneYearAgo: "
- + oneYearAgo.getTimeInMillis());
- return true;
- }
- return false;
- }
-
static boolean isDateTimeOlderThanDuration(long timestamp, Duration duration) {
Instant nowMinusDuration = Instant.now().minus(duration);
Instant dateTime = Instant.ofEpochMilli(timestamp);
diff --git a/android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java b/android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java
index 05ec2a39e7..87c750dfcd 100644
--- a/android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java
+++ b/android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java
@@ -1086,15 +1086,21 @@ class MceStateMachine extends StateMachine {
if (message == null) {
return;
}
+
+ MessageMetadata metadata = mMessages.get(request.getHandle());
+ if (metadata == null) {
+ Log.e(TAG, "No request record of received message, handle=" + request.getHandle());
+ return;
+ }
+
mDatabase.storeMessage(
- message,
- request.getHandle(),
- mMessages.get(request.getHandle()).getTimestamp(),
- mMessages.get(request.getHandle()).getSeen());
+ message, request.getHandle(), metadata.getTimestamp(), metadata.getSeen());
+
if (!INBOX_PATH.equalsIgnoreCase(message.getFolder())) {
Log.d(TAG, "Ignoring message received in " + message.getFolder() + ".");
return;
}
+
switch (message.getType()) {
case SMS_CDMA:
case SMS_GSM:
@@ -1104,7 +1110,6 @@ class MceStateMachine extends StateMachine {
Log.d(TAG, "Recipients" + message.getRecipients().toString());
// Grab the message metadata and update the cached read status from the bMessage
- MessageMetadata metadata = mMessages.get(request.getHandle());
metadata.setRead(request.getMessage().getStatus() == Bmessage.Status.READ);
Intent intent = new Intent();
diff --git a/android/app/src/com/android/bluetooth/mcp/McpService.java b/android/app/src/com/android/bluetooth/mcp/McpService.java
index 8eb316770b..c05b844634 100644
--- a/android/app/src/com/android/bluetooth/mcp/McpService.java
+++ b/android/app/src/com/android/bluetooth/mcp/McpService.java
@@ -24,15 +24,12 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetoothMcpServiceManager;
import android.content.AttributionSource;
import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
import android.os.ParcelUuid;
import android.sysprop.BluetoothProperties;
import android.util.Log;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.ProfileService;
-import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.le_audio.LeAudioService;
import com.android.internal.annotations.VisibleForTesting;
@@ -48,7 +45,6 @@ public class McpService extends ProfileService {
private final MediaControlProfile mGmcs;
private final Map<BluetoothDevice, Integer> mDeviceAuthorizations = new HashMap<>();
- private final Handler mHandler = new Handler(Looper.getMainLooper());
public McpService(Context ctx) {
this(ctx, null);
@@ -102,16 +98,7 @@ public class McpService extends ProfileService {
// Mark service as started
setMcpService(this);
- if (Flags.leaudioSynchronizeStart()) {
- mGmcs.init();
- return;
- }
- mHandler.post(
- () -> {
- if (isAvailable()) {
- mGmcs.init();
- }
- });
+ mGmcs.init();
}
@Override
diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
index 8cbd32cfba..6efdb17d66 100644
--- a/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
+++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
@@ -445,9 +445,7 @@ class BluetoothOppNotification {
intent.setDataAndNormalize(Uri.parse(BluetoothShare.CONTENT_URI + "/" + item.id));
b.setContentIntent(
PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE));
- if (Flags.oppFixMultipleNotificationsIssues()) {
- b.setGroup(NOTIFICATION_GROUP_KEY_PROGRESS);
- }
+ b.setGroup(NOTIFICATION_GROUP_KEY_PROGRESS);
mNotificationMgr.notify(NOTIFICATION_ID_PROGRESS, b.build());
}
}
@@ -502,25 +500,14 @@ class BluetoothOppNotification {
BluetoothOppUtility.formatResultText(
outboundSuccNumber, outboundFailNumber, mContext);
- PendingIntent pi;
- if (Flags.oppStartActivityDirectlyFromNotification()) {
- Intent in = new Intent(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
- in.setClass(mContext, BluetoothOppTransferHistory.class);
- in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- pi = PendingIntent.getActivity(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
- } else {
- Intent in =
- new Intent(Constants.ACTION_OPEN_OUTBOUND_TRANSFER)
- .setClassName(mContext, BluetoothOppReceiver.class.getName());
- pi = PendingIntent.getBroadcast(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
- }
+ Intent in = new Intent(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
+ in.setClass(mContext, BluetoothOppTransferHistory.class);
+ in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ PendingIntent pi =
+ PendingIntent.getActivity(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
Intent deleteIntent = new Intent(mContext, BluetoothOppReceiver.class);
- if (Flags.oppFixMultipleNotificationsIssues()) {
- deleteIntent.setAction(Constants.ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER);
- } else {
- deleteIntent.setAction(Constants.ACTION_COMPLETE_HIDE);
- }
+ deleteIntent.setAction(Constants.ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER);
Notification.Builder b =
new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL)
@@ -542,10 +529,8 @@ class BluetoothOppNotification {
deleteIntent,
PendingIntent.FLAG_IMMUTABLE))
.setWhen(timeStamp)
- .setLocalOnly(true);
- if (Flags.oppFixMultipleNotificationsIssues()) {
- b.setGroup(NOTIFICATION_GROUP_KEY_TRANSFER_COMPLETE);
- }
+ .setLocalOnly(true)
+ .setGroup(NOTIFICATION_GROUP_KEY_TRANSFER_COMPLETE);
mNotificationMgr.notify(NOTIFICATION_ID_OUTBOUND_COMPLETE, b.build());
} else {
if (mNotificationMgr != null) {
@@ -591,25 +576,14 @@ class BluetoothOppNotification {
BluetoothOppUtility.formatResultText(
inboundSuccNumber, inboundFailNumber, mContext);
- PendingIntent pi;
- if (Flags.oppStartActivityDirectlyFromNotification()) {
- Intent in = new Intent(Constants.ACTION_OPEN_INBOUND_TRANSFER);
- in.setClass(mContext, BluetoothOppTransferHistory.class);
- in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- pi = PendingIntent.getActivity(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
- } else {
- Intent in =
- new Intent(Constants.ACTION_OPEN_INBOUND_TRANSFER)
- .setClassName(mContext, BluetoothOppReceiver.class.getName());
- pi = PendingIntent.getBroadcast(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
- }
+ Intent in = new Intent(Constants.ACTION_OPEN_INBOUND_TRANSFER);
+ in.setClass(mContext, BluetoothOppTransferHistory.class);
+ in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ PendingIntent pi =
+ PendingIntent.getActivity(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
Intent deleteIntent = new Intent(mContext, BluetoothOppReceiver.class);
- if (Flags.oppFixMultipleNotificationsIssues()) {
- deleteIntent.setAction(Constants.ACTION_HIDE_COMPLETED_INBOUND_TRANSFER);
- } else {
- deleteIntent.setAction(Constants.ACTION_COMPLETE_HIDE);
- }
+ deleteIntent.setAction(Constants.ACTION_HIDE_COMPLETED_INBOUND_TRANSFER);
Notification.Builder b =
new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL)
@@ -631,10 +605,8 @@ class BluetoothOppNotification {
deleteIntent,
PendingIntent.FLAG_IMMUTABLE))
.setWhen(timeStamp)
- .setLocalOnly(true);
- if (Flags.oppFixMultipleNotificationsIssues()) {
- b.setGroup(NOTIFICATION_GROUP_KEY_TRANSFER_COMPLETE);
- }
+ .setLocalOnly(true)
+ .setGroup(NOTIFICATION_GROUP_KEY_TRANSFER_COMPLETE);
mNotificationMgr.notify(NOTIFICATION_ID_INBOUND_COMPLETE, b.build());
} else {
if (mNotificationMgr != null) {
@@ -643,7 +615,7 @@ class BluetoothOppNotification {
}
}
- if (Flags.oppFixMultipleNotificationsIssues() && inboundNum > 0 && outboundNum > 0) {
+ if (inboundNum > 0 && outboundNum > 0) {
Notification.Builder b =
new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL)
.setGroup(NOTIFICATION_GROUP_KEY_TRANSFER_COMPLETE)
@@ -710,30 +682,18 @@ class BluetoothOppNotification {
PendingIntent.FLAG_IMMUTABLE))
.build();
- PendingIntent contentIntent;
- if (Flags.oppStartActivityDirectlyFromNotification()) {
- Intent intent = new Intent(mContext, BluetoothOppIncomingFileConfirmActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setDataAndNormalize(contentUri);
- contentIntent =
- PendingIntent.getActivity(
- mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
- } else {
- contentIntent =
- PendingIntent.getBroadcast(
- mContext,
- 0,
- new Intent(baseIntent)
- .setAction(Constants.ACTION_INCOMING_FILE_CONFIRM),
- PendingIntent.FLAG_IMMUTABLE);
- }
+ Intent in = new Intent(mContext, BluetoothOppIncomingFileConfirmActivity.class);
+ in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ in.setDataAndNormalize(contentUri);
+ PendingIntent pi =
+ PendingIntent.getActivity(mContext, 0, in, PendingIntent.FLAG_IMMUTABLE);
Notification.Builder publicNotificationBuilder =
new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setWhen(info.mTimeStamp)
- .setContentIntent(contentIntent)
+ .setContentIntent(pi)
.setDeleteIntent(
PendingIntent.getBroadcast(
mContext,
@@ -760,17 +720,15 @@ class BluetoothOppNotification {
fileNameSafe)))
.setSubText(Formatter.formatFileSize(mContext, info.mTotalBytes))
.setSmallIcon(R.drawable.ic_bluetooth_file_transfer_notification)
- .setLocalOnly(true);
- if (Flags.oppFixMultipleNotificationsIssues()) {
- publicNotificationBuilder.setGroup(NOTIFICATION_GROUP_KEY_INCOMING_FILE_CONFIRM);
- }
+ .setLocalOnly(true)
+ .setGroup(NOTIFICATION_GROUP_KEY_INCOMING_FILE_CONFIRM);
Notification.Builder builder =
new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setWhen(info.mTimeStamp)
- .setContentIntent(contentIntent)
+ .setContentIntent(pi)
.setDeleteIntent(
PendingIntent.getBroadcast(
mContext,
@@ -801,10 +759,8 @@ class BluetoothOppNotification {
.setVisibility(Notification.VISIBILITY_PRIVATE)
.addAction(actionDecline)
.addAction(actionAccept)
- .setPublicVersion(publicNotificationBuilder.build());
- if (Flags.oppFixMultipleNotificationsIssues()) {
- builder.setGroup(NOTIFICATION_GROUP_KEY_INCOMING_FILE_CONFIRM);
- }
+ .setPublicVersion(publicNotificationBuilder.build())
+ .setGroup(NOTIFICATION_GROUP_KEY_INCOMING_FILE_CONFIRM);
mNotificationMgr.notify(NOTIFICATION_ID_PROGRESS, builder.build());
}
cursor.close();
diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
index 9b7a7329a8..e0cade561d 100644
--- a/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
+++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
@@ -100,15 +100,6 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
toastMsg = context.getString(R.string.bt_toast_4, deviceName);
}
Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show();
- } else if (action.equals(Constants.ACTION_INCOMING_FILE_CONFIRM)
- && !Flags.oppStartActivityDirectlyFromNotification()) {
- Log.v(TAG, "Receiver ACTION_INCOMING_FILE_CONFIRM");
-
- Uri uri = intent.getData();
- Intent in = new Intent(context, BluetoothOppIncomingFileConfirmActivity.class);
- in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- in.setDataAndNormalize(uri);
- context.startActivity(in);
} else if (action.equals(Constants.ACTION_DECLINE)) {
Log.v(TAG, "Receiver ACTION_DECLINE");
@@ -164,22 +155,6 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
context.startActivity(in);
}
- } else if (action.equals(Constants.ACTION_OPEN_OUTBOUND_TRANSFER)
- && !Flags.oppStartActivityDirectlyFromNotification()) {
- Log.v(TAG, "Received ACTION_OPEN_OUTBOUND_TRANSFER.");
-
- Intent in = new Intent(context, BluetoothOppTransferHistory.class);
- in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- in.putExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
- context.startActivity(in);
- } else if (action.equals(Constants.ACTION_OPEN_INBOUND_TRANSFER)
- && !Flags.oppStartActivityDirectlyFromNotification()) {
- Log.v(TAG, "Received ACTION_OPEN_INBOUND_TRANSFER.");
-
- Intent in = new Intent(context, BluetoothOppTransferHistory.class);
- in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- in.putExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_INBOUND);
- context.startActivity(in);
} else if (action.equals(Constants.ACTION_HIDE)) {
Log.v(TAG, "Receiver hide for " + intent.getData());
Cursor cursor =
@@ -214,20 +189,7 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
}
cursor.close();
}
- } else if (action.equals(Constants.ACTION_COMPLETE_HIDE)
- && !Flags.oppFixMultipleNotificationsIssues()) {
- Log.v(TAG, "Receiver ACTION_COMPLETE_HIDE");
- ContentValues updateValues = new ContentValues();
- updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN);
- BluetoothMethodProxy.getInstance()
- .contentResolverUpdate(
- context.getContentResolver(),
- BluetoothShare.CONTENT_URI,
- updateValues,
- BluetoothOppNotification.WHERE_COMPLETED,
- null);
- } else if (action.equals(Constants.ACTION_HIDE_COMPLETED_INBOUND_TRANSFER)
- && Flags.oppFixMultipleNotificationsIssues()) {
+ } else if (action.equals(Constants.ACTION_HIDE_COMPLETED_INBOUND_TRANSFER)) {
Log.v(TAG, "Received ACTION_HIDE_COMPLETED_INBOUND_TRANSFER");
ContentValues updateValues = new ContentValues();
updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN);
@@ -238,8 +200,7 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
updateValues,
BluetoothOppNotification.WHERE_COMPLETED_INBOUND,
null);
- } else if (action.equals(Constants.ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER)
- && Flags.oppFixMultipleNotificationsIssues()) {
+ } else if (action.equals(Constants.ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER)) {
Log.v(TAG, "Received ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER");
ContentValues updateValues = new ContentValues();
updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN);
diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
index 16056cde79..2d727f9fdf 100644
--- a/android/app/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
+++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
@@ -32,6 +32,8 @@
package com.android.bluetooth.opp;
+import static android.os.UserHandle.myUserId;
+
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.content.ContentResolver;
@@ -41,6 +43,7 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.provider.OpenableColumns;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -53,12 +56,13 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.Objects;
/**
* This class stores information about a single sending file It will only be used for outbound
* share.
*/
-// Next tag value for ContentProfileErrorReportUtils.report(): 15
+// Next tag value for ContentProfileErrorReportUtils.report(): 16
public class BluetoothOppSendFileInfo {
private static final String TAG = "BluetoothOppSendFileInfo";
@@ -124,6 +128,16 @@ public class BluetoothOppSendFileInfo {
return SEND_FILE_INFO_ERROR;
}
+ if (isContentUriForOtherUser(uri)) {
+ Log.e(TAG, "Uri: " + uri + " is invalid for user " + myUserId());
+ ContentProfileErrorReportUtils.report(
+ BluetoothProfile.OPP,
+ BluetoothProtoEnums.BLUETOOTH_OPP_SEND_FILE_INFO,
+ BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_ERROR,
+ 15);
+ return SEND_FILE_INFO_ERROR;
+ }
+
contentType = contentResolver.getType(uri);
Cursor metadataCursor;
try {
@@ -353,6 +367,12 @@ public class BluetoothOppSendFileInfo {
return new BluetoothOppSendFileInfo(fileName, contentType, length, is, 0);
}
+ private static boolean isContentUriForOtherUser(Uri uri) {
+ String uriUserId = uri.getUserInfo();
+ return !TextUtils.isEmpty(uriUserId)
+ && !Objects.equals(uriUserId, String.valueOf(myUserId()));
+ }
+
private static long getStreamSize(FileInputStream is) throws IOException {
long length = 0;
byte[] unused = new byte[4096];
diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
index c8ae64dd24..ae9283050e 100644
--- a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
+++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
@@ -113,18 +113,10 @@ public class BluetoothOppTransferHistory extends Activity
mListView = (ListView) findViewById(R.id.list);
mListView.setEmptyView(findViewById(R.id.empty));
- String direction;
-
- boolean isOutbound = false;
-
- if (Flags.oppStartActivityDirectlyFromNotification()) {
- String action = getIntent().getAction();
- isOutbound = Constants.ACTION_OPEN_OUTBOUND_TRANSFER.equals(action);
- } else {
- int dir = getIntent().getIntExtra(Constants.EXTRA_DIRECTION, 0);
- isOutbound = (dir == BluetoothShare.DIRECTION_OUTBOUND);
- }
+ boolean isOutbound =
+ Constants.ACTION_OPEN_OUTBOUND_TRANSFER.equals(getIntent().getAction());
+ String direction;
if (isOutbound) {
setTitle(getText(R.string.outbound_history_title));
direction =
diff --git a/android/app/src/com/android/bluetooth/opp/Constants.java b/android/app/src/com/android/bluetooth/opp/Constants.java
index e68364be9f..67e00ec343 100644
--- a/android/app/src/com/android/bluetooth/opp/Constants.java
+++ b/android/app/src/com/android/bluetooth/opp/Constants.java
@@ -166,14 +166,6 @@ public class Constants {
/** the intent that gets sent when declining the incoming file confirmation notification */
static final String ACTION_DECLINE = "android.btopp.intent.action.DECLINE";
- /**
- * The intent that gets sent when deleting the notifications of outbound and inbound completed
- * transfer.
- */
- // TODO(b/323096132): Remove this variable when the flag
- // opp_fix_multiple_notifications_issues is ramped up.
- static final String ACTION_COMPLETE_HIDE = "android.btopp.intent.action.HIDE_COMPLETE";
-
/** The intent that gets sent when deleting the notifications of completed inbound transfer. */
static final String ACTION_HIDE_COMPLETED_INBOUND_TRANSFER =
"android.btopp.intent.action.HIDE_COMPLETED_INBOUND_TRANSFER";
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientContactsStorage.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientContactsStorage.java
index f89fcec616..3923d4631d 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientContactsStorage.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientContactsStorage.java
@@ -224,6 +224,13 @@ class PbapClientContactsStorage {
*
* <p>This function also associates the phonebook metadata with the contact for easy
* per-phonebook cleanup operations.
+ *
+ * <p>Contacts are inserted in smaller batches so they can be loaded in chunks as opposed to
+ * shown all at once in the UI. This also prevents us from hitting the binder transaction limit.
+ *
+ * @param account The account to insert contacts against
+ * @param phonebook The phonebook these contacts belong to
+ * @param contacts The list of contacts to insert
*/
private boolean insertContacts(Account account, String phonebook, List<VCardEntry> contacts) {
if (!mStorageInitialized) {
@@ -374,11 +381,15 @@ class PbapClientContactsStorage {
/**
* Insert call history entries of a given type
*
+ * <p>These call logs are inserted in smaller batches so they can be loaded in chunks as opposed
+ * to shown all at once in the UI. This also prevents us from hitting the binder transaction
+ * limit
+ *
* @param account The account to insert call logs against
- * @param type The type of call history provided
- * @param history The call history to insert
+ * @param type The type of call provided
+ * @param history The list of calls to add
+ * @return True if successful, False otherwise
*/
- @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate
private boolean insertCallHistory(Account account, int type, List<VCardEntry> history) {
if (!mStorageInitialized) {
Log.w(TAG, "insertCallHistory: Failed, storage not ready");
@@ -405,61 +416,114 @@ class PbapClientContactsStorage {
try {
Log.i(
TAG,
- "insertCallHistory: Inserting call history, type="
+ "insertCallHistory: inserting call history, account="
+ + account
+ + ", type="
+ type
+ ", count="
+ history.size());
- ArrayList<ContentProviderOperation> ops = new ArrayList<>();
- for (VCardEntry vcard : history) {
- ContentValues values = new ContentValues();
- values.put(CallLog.Calls.TYPE, type);
- values.put(Calls.PHONE_ACCOUNT_ID, account.name);
-
- List<PhoneData> phones = vcard.getPhoneList();
- if (phones == null
- || phones.get(0).getNumber().equals(";")
- || phones.get(0).getNumber().length() == 0) {
- values.put(CallLog.Calls.NUMBER, "");
- } else {
- String phoneNumber = phones.get(0).getNumber();
- values.put(CallLog.Calls.NUMBER, phoneNumber);
- }
+ ContentResolver contactsProvider = mContext.getContentResolver();
+ ArrayList<ContentProviderOperation> operations = new ArrayList<>();
- List<Pair<String, String>> irmc = vcard.getUnknownXData();
- SimpleDateFormat parser = new SimpleDateFormat(TIMESTAMP_FORMAT);
- if (irmc != null) {
- for (Pair<String, String> pair : irmc) {
- if (pair.first.startsWith(CALL_LOG_TIMESTAMP_PROPERTY)) {
- try {
- values.put(CallLog.Calls.DATE, parser.parse(pair.second).getTime());
- } catch (ParseException e) {
- Log.d(TAG, "Failed to parse date, value=" + pair.second);
- }
- }
- }
+ // Group insert operations together to minimize inter process communication and improve
+ // processing time.
+ for (VCardEntry callLog : history) {
+ if (Thread.currentThread().isInterrupted()) {
+ Log.e(TAG, "insertCallHistory: Interrupted during insert");
+ break;
}
- ops.add(
- ContentProviderOperation.newInsert(CallLog.Calls.CONTENT_URI)
- .withValues(values)
- .withYieldAllowed(true)
- .build());
+ // Append current call to list of insert operations.
+ int numberOfOperations = operations.size();
+ constructInsertOperationsForCallLog(account, type, callLog, operations);
+
+ if (operations.size() >= CONTACTS_INSERT_BATCH_SIZE) {
+ Log.i(
+ TAG,
+ "insertCallHistory: batch full, operations.size()="
+ + operations.size()
+ + ", batch_size="
+ + CONTACTS_INSERT_BATCH_SIZE);
+
+ // If we have exceeded the limit of the insert operations, remove the latest
+ // call and submit.
+ operations.subList(numberOfOperations, operations.size()).clear();
+
+ contactsProvider.applyBatch(CallLog.AUTHORITY, operations);
+
+ // Re-add the current call log operation(s) to the list
+ operations = constructInsertOperationsForCallLog(account, type, callLog, null);
+
+ Log.i(
+ TAG,
+ "insertCallHistory: batch complete, operations.size()="
+ + operations.size());
+ }
}
- mContext.getContentResolver().applyBatch(CallLog.AUTHORITY, ops);
- Log.d(TAG, "Inserted call logs, type=" + type);
- } catch (RemoteException | OperationApplicationException e) {
- Log.w(TAG, "Failed to insert call log, type=" + type, e);
- return false;
- } finally {
- synchronized (this) {
- this.notify();
+ // Apply any unsubmitted calls
+ if (operations.size() > 0) {
+ contactsProvider.applyBatch(CallLog.AUTHORITY, operations);
+ operations.clear();
}
+ Log.i(TAG, "insertCallHistory: insert complete, count=" + history.size());
+ } catch (OperationApplicationException | RemoteException | NumberFormatException e) {
+ Log.e(TAG, "insertCallHistory: Exception occurred while processing call log pull: ", e);
+ return false;
}
return true;
}
+ // TODO: b/365629730 -- JavaUtilDate: prefer Instant or LocalDate
+ // NonApiType: For convenience, as the applyBatch API actually takes an ArrayList above
+ @SuppressWarnings({"JavaUtilDate", "NonApiType"})
+ private ArrayList<ContentProviderOperation> constructInsertOperationsForCallLog(
+ Account account,
+ int type,
+ VCardEntry call,
+ ArrayList<ContentProviderOperation> operations) {
+ if (operations == null) {
+ operations = new ArrayList<ContentProviderOperation>();
+ }
+
+ ContentValues values = new ContentValues();
+ values.put(Calls.PHONE_ACCOUNT_ID, account.name);
+ values.put(CallLog.Calls.TYPE, type);
+
+ List<PhoneData> phones = call.getPhoneList();
+ if (phones == null
+ || phones.get(0).getNumber().equals(";")
+ || phones.get(0).getNumber().length() == 0) {
+ values.put(CallLog.Calls.NUMBER, "");
+ } else {
+ String phoneNumber = phones.get(0).getNumber();
+ values.put(CallLog.Calls.NUMBER, phoneNumber);
+ }
+
+ List<Pair<String, String>> irmc = call.getUnknownXData();
+ SimpleDateFormat parser = new SimpleDateFormat(TIMESTAMP_FORMAT);
+ if (irmc != null) {
+ for (Pair<String, String> pair : irmc) {
+ if (pair.first.startsWith(CALL_LOG_TIMESTAMP_PROPERTY)) {
+ try {
+ values.put(CallLog.Calls.DATE, parser.parse(pair.second).getTime());
+ } catch (ParseException e) {
+ Log.d(TAG, "Failed to parse date, value=" + pair.second);
+ }
+ }
+ }
+ }
+
+ operations.add(
+ ContentProviderOperation.newInsert(CallLog.Calls.CONTENT_URI)
+ .withValues(values)
+ .withYieldAllowed(true)
+ .build());
+
+ return operations;
+ }
+
/**
* Remove all call history associated with this client's account
*
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
index c2aae98269..f5e4898ee1 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
@@ -478,11 +478,7 @@ public class PbapClientService extends ProfileService {
Log.e(TAG, "No Statemachine found for the device=" + device.toString());
return;
}
-
- smOld.obtainMessage(
- PbapClientStateMachineOld.MSG_SDP_COMPLETE,
- new PbapSdpRecord(device, pseRecord))
- .sendToTarget();
+ smOld.onSdpResultReceived(status, new PbapSdpRecord(device, pseRecord));
}
}
}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachineOld.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachineOld.java
index 420ae07ace..c07dadc62c 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachineOld.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachineOld.java
@@ -76,7 +76,6 @@ class PbapClientStateMachineOld extends StateMachine {
// Messages for handling connect/disconnect requests.
private static final int MSG_DISCONNECT = 2;
- static final int MSG_SDP_COMPLETE = 9;
// Messages for handling error conditions.
private static final int MSG_CONNECT_TIMEOUT = 3;
@@ -87,9 +86,20 @@ class PbapClientStateMachineOld extends StateMachine {
static final int MSG_CONNECTION_FAILED = 6;
static final int MSG_CONNECTION_CLOSED = 7;
static final int MSG_RESUME_DOWNLOAD = 8;
+ static final int MSG_SDP_COMPLETE = 9;
+ static final int MSG_SDP_BUSY = 10;
+ static final int MSG_SDP_FAIL = 11;
+ // Constants for SDP. Note that these values come from the native stack, but no centralized
+ // constants exist for them as part of the various SDP APIs.
+ public static final int SDP_SUCCESS = 0;
+ public static final int SDP_FAILED = 1;
+ public static final int SDP_BUSY = 2;
+
+ // All times are in milliseconds
static final int CONNECT_TIMEOUT = 10000;
static final int DISCONNECT_TIMEOUT = 3000;
+ static final int SDP_BUSY_RETRY_DELAY = 20;
private static final int LOCAL_SUPPORTED_FEATURES =
PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT | PbapSdpRecord.FEATURE_DOWNLOADING;
@@ -210,14 +220,40 @@ class PbapClientStateMachineOld extends StateMachine {
break;
case MSG_SDP_COMPLETE:
+ removeMessages(MSG_SDP_BUSY);
PbapClientConnectionHandler connectionHandler = mConnectionHandler;
if (connectionHandler != null) {
+ if (message.obj == null) {
+ Log.w(TAG, "Received SDP response without valid PSE record ");
+ }
connectionHandler
.obtainMessage(PbapClientConnectionHandler.MSG_CONNECT, message.obj)
.sendToTarget();
+ } else {
+ Log.w(TAG, "Received SDP complete without connection handler");
}
break;
+ case MSG_SDP_BUSY:
+ removeMessages(MSG_SDP_BUSY);
+ Log.d(TAG, "Received SDP busy, try again");
+ mCurrentDevice.sdpSearch(BluetoothUuid.PBAP_PSE);
+ break;
+
+ case MSG_SDP_FAIL:
+ removeMessages(MSG_SDP_BUSY);
+ int status = message.arg1;
+ Log.w(TAG, "SDP failed status:" + status + ", starting disconnect");
+ transitionTo(mDisconnecting);
+ break;
+
+ case MSG_RESUME_DOWNLOAD:
+ Log.i(
+ TAG,
+ "Received request to download phonebook but still in state "
+ + this.getName());
+ break;
+
default:
Log.w(TAG, "Received unexpected message while Connecting");
return NOT_HANDLED;
@@ -317,6 +353,24 @@ class PbapClientStateMachineOld extends StateMachine {
}
}
+ /** Notify of SDP completion. */
+ public void onSdpResultReceived(int status, PbapSdpRecord record) {
+ Log.d(TAG, "Received SDP Result, status=" + status + ", record=" + record);
+ switch (status) {
+ case SDP_SUCCESS:
+ sendMessage(PbapClientStateMachineOld.MSG_SDP_COMPLETE, record);
+ break;
+
+ case SDP_BUSY:
+ sendMessageDelayed(PbapClientStateMachineOld.MSG_SDP_BUSY, SDP_BUSY_RETRY_DELAY);
+ break;
+
+ default:
+ sendMessage(PbapClientStateMachineOld.MSG_SDP_FAIL);
+ break;
+ }
+ }
+
/** Trigger a contacts download if the user is unlocked and our accounts are available to us */
private void downloadIfReady() {
boolean userReady = mUserManager.isUserUnlocked();
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexClient.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexClient.java
index 760b67d900..8099c269c8 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexClient.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexClient.java
@@ -17,6 +17,7 @@
package com.android.bluetooth.pbapclient;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import android.accounts.Account;
import android.annotation.RequiresPermission;
@@ -468,7 +469,9 @@ class PbapClientObexClient {
/* Utilize SDP, if available, to create a socket connection over L2CAP, RFCOMM specified
* channel, or RFCOMM default channel. */
- @RequiresPermission(BLUETOOTH_CONNECT)
+ @RequiresPermission(
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
private PbapClientSocket connectSocket(int transport, int channelOrPsm) {
debug(
"Connect socket, transport="
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientSocket.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientSocket.java
index 4a17721a3e..7438a02fe9 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientSocket.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientSocket.java
@@ -17,6 +17,7 @@
package com.android.bluetooth.pbapclient;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
@@ -101,7 +102,9 @@ public class PbapClientSocket {
}
/** Invokes the underlying BluetoothSocket#connect(), or does nothing if a socket is injected */
- @RequiresPermission(BLUETOOTH_CONNECT)
+ @RequiresPermission(
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
public void connect() throws IOException {
if (mSocket != null) {
mSocket.connect();
diff --git a/android/app/src/com/android/bluetooth/telephony/BluetoothCall.java b/android/app/src/com/android/bluetooth/telephony/BluetoothCall.java
index 4cea94633c..329fa6240e 100644
--- a/android/app/src/com/android/bluetooth/telephony/BluetoothCall.java
+++ b/android/app/src/com/android/bluetooth/telephony/BluetoothCall.java
@@ -26,7 +26,6 @@ import android.telecom.InCallService;
import android.telecom.PhoneAccountHandle;
import com.android.bluetooth.apishim.BluetoothCallShimImpl;
-import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
@@ -42,8 +41,7 @@ import java.util.UUID;
* functioning of the BluetoothInCallService class, the final class must be put into a container
* that can be mocked correctly.
*/
-@VisibleForTesting
-public class BluetoothCall {
+class BluetoothCall {
private Call mCall;
private UUID mCallId;
diff --git a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
index bd0b40ec4f..2fa94bd27e 100644
--- a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
+++ b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
@@ -624,28 +624,31 @@ public class BluetoothInCallService extends InCallService {
@RequiresPermission(allOf = {BLUETOOTH_CONNECT, MODIFY_PHONE_STATE})
public void onCallAdded(BluetoothCall call) {
- if (call.isExternalCall()) {
- Log.d(TAG, "onCallAdded: external call");
- return;
- }
- if (!mBluetoothCallHashMap.containsKey(call.getId())) {
- Log.i(TAG, "onCallAdded");
- CallStateCallback callback = new CallStateCallback(call.getState());
- mCallbacks.put(call.getId(), callback);
- call.registerCallback(callback);
-
- mBluetoothCallHashMap.put(call.getId(), call);
- if (!call.isConference()) {
- mMaxNumberOfCalls = Integer.max(mMaxNumberOfCalls, mBluetoothCallHashMap.size());
+ synchronized (LOCK) {
+ if (call.isExternalCall()) {
+ Log.d(TAG, "onCallAdded: external call");
+ return;
}
- updateHeadsetWithCallState(false /* force */);
+ if (!mBluetoothCallHashMap.containsKey(call.getId())) {
+ Log.i(TAG, "onCallAdded");
+ CallStateCallback callback = new CallStateCallback(call.getState());
+ mCallbacks.put(call.getId(), callback);
+ call.registerCallback(callback);
- BluetoothLeCall tbsCall = createTbsCall(call);
- if (mBluetoothLeCallControl != null && tbsCall != null) {
- mBluetoothLeCallControl.onCallAdded(tbsCall);
+ mBluetoothCallHashMap.put(call.getId(), call);
+ if (!call.isConference()) {
+ mMaxNumberOfCalls =
+ Integer.max(mMaxNumberOfCalls, mBluetoothCallHashMap.size());
+ }
+ updateHeadsetWithCallState(false /* force */);
+
+ BluetoothLeCall tbsCall = createTbsCall(call);
+ if (mBluetoothLeCallControl != null && tbsCall != null) {
+ mBluetoothLeCallControl.onCallAdded(tbsCall);
+ }
+ } else {
+ Log.i(TAG, "onCallAdded: call already exists");
}
- } else {
- Log.i(TAG, "onCallAdded: call already exists");
}
}
@@ -694,63 +697,66 @@ public class BluetoothInCallService extends InCallService {
*/
@RequiresPermission(allOf = {BLUETOOTH_CONNECT, MODIFY_PHONE_STATE})
public void onCallRemoved(BluetoothCall call, boolean forceRemoveCallback) {
- Log.i(TAG, "onCallRemoved, forceRemoveCallback=" + forceRemoveCallback);
- CallStateCallback callback = getCallback(call);
- if (callback != null && (forceRemoveCallback || !call.isExternalCall())) {
- call.unregisterCallback(callback);
- }
-
- if (mBluetoothCallHashMap.containsKey(call.getId())) {
- mBluetoothCallHashMap.remove(call.getId());
-
- DisconnectCause cause = call.getDisconnectCause();
- if (cause != null && cause.getCode() == DisconnectCause.OTHER) {
- Log.d(TAG, "add inference call with reason: " + cause.getReason());
- mBluetoothCallQueue.add(call.getId());
- mBluetoothConferenceCallInference.put(call.getId(), call);
- if (Flags.maintainCallIndexAfterConference()) {
- // If the disconnect is due to call merge, store the index for future use.
- if (cause.getReason() != null
- && cause.getReason().equals("IMS_MERGED_SUCCESSFULLY")) {
- if (!mConferenceCallClccIndexMap.containsKey(getClccMapKey(call))) {
- if (call.mClccIndex > -1) {
- mConferenceCallClccIndexMap.put(
- getClccMapKey(call), call.mClccIndex);
+ synchronized (LOCK) {
+ Log.i(TAG, "onCallRemoved, forceRemoveCallback=" + forceRemoveCallback);
+ CallStateCallback callback = getCallback(call);
+ if (callback != null && (forceRemoveCallback || !call.isExternalCall())) {
+ call.unregisterCallback(callback);
+ }
+
+ if (mBluetoothCallHashMap.containsKey(call.getId())) {
+ mBluetoothCallHashMap.remove(call.getId());
+
+ DisconnectCause cause = call.getDisconnectCause();
+ if (cause != null && cause.getCode() == DisconnectCause.OTHER) {
+ Log.d(TAG, "add inference call with reason: " + cause.getReason());
+ mBluetoothCallQueue.add(call.getId());
+ mBluetoothConferenceCallInference.put(call.getId(), call);
+ if (Flags.maintainCallIndexAfterConference()) {
+ // If the disconnect is due to call merge, store the index for future use.
+ if (cause.getReason() != null
+ && cause.getReason().equals("IMS_MERGED_SUCCESSFULLY")) {
+ if (!mConferenceCallClccIndexMap.containsKey(getClccMapKey(call))) {
+ if (call.mClccIndex > -1) {
+ mConferenceCallClccIndexMap.put(
+ getClccMapKey(call), call.mClccIndex);
+ }
}
}
}
- }
- // queue size limited to 2 because merge operation only happens on 2 calls
- // we are only interested in last 2 calls merged
- if (mBluetoothCallQueue.size() > 2) {
- Integer callId = mBluetoothCallQueue.peek();
- mBluetoothCallQueue.remove();
- mBluetoothConferenceCallInference.remove(callId);
+ // queue size limited to 2 because merge operation only happens on 2 calls
+ // we are only interested in last 2 calls merged
+ if (mBluetoothCallQueue.size() > 2) {
+ Integer callId = mBluetoothCallQueue.peek();
+ mBluetoothCallQueue.remove();
+ mBluetoothConferenceCallInference.remove(callId);
+ }
+ }
+ // As there is at most 1 conference call, so clear inference when parent call ends
+ if (call.isConference()) {
+ Log.d(TAG, "conference call ends, clear inference");
+ mBluetoothConferenceCallInference.clear();
+ mBluetoothCallQueue.clear();
}
}
- // As there is at most 1 conference call, so clear inference when parent call ends
- if (call.isConference()) {
- Log.d(TAG, "conference call ends, clear inference");
- mBluetoothConferenceCallInference.clear();
- mBluetoothCallQueue.clear();
- }
- }
- updateHeadsetWithCallState(false /* force */);
+ updateHeadsetWithCallState(false /* force */);
- if (Flags.maintainCallIndexAfterConference() && mConferenceCallClccIndexMap.size() > 0) {
- int anyActiveCalls = mCallInfo.isNullCall(mCallInfo.getActiveCall()) ? 0 : 1;
- int numHeldCalls = mCallInfo.getNumHeldCalls();
- // If no call is active or held clear the hashmap.
- if (anyActiveCalls == 0 && numHeldCalls == 0) {
- mConferenceCallClccIndexMap.clear();
+ if (Flags.maintainCallIndexAfterConference()
+ && mConferenceCallClccIndexMap.size() > 0) {
+ int anyActiveCalls = mCallInfo.isNullCall(mCallInfo.getActiveCall()) ? 0 : 1;
+ int numHeldCalls = mCallInfo.getNumHeldCalls();
+ // If no call is active or held clear the hashmap.
+ if (anyActiveCalls == 0 && numHeldCalls == 0) {
+ mConferenceCallClccIndexMap.clear();
+ }
}
- }
- if (mBluetoothLeCallControl != null) {
- mBluetoothLeCallControl.onCallRemoved(
- call.getTbsCallId(), getTbsTerminationReason(call));
+ if (mBluetoothLeCallControl != null) {
+ mBluetoothLeCallControl.onCallRemoved(
+ call.getTbsCallId(), getTbsTerminationReason(call));
+ }
}
}
diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java
index bbdb35af65..e0868e416a 100644
--- a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java
+++ b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java
@@ -27,6 +27,9 @@ import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
+import static android.bluetooth.IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID;
+import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
+import static android.bluetooth.IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME;
import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNullElseGet;
@@ -41,8 +44,6 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IAudioInputCallback;
-import android.bluetooth.IBluetoothCsipSetCoordinator;
-import android.bluetooth.IBluetoothLeAudio;
import android.bluetooth.IBluetoothVolumeControl;
import android.bluetooth.IBluetoothVolumeControlCallback;
import android.content.AttributionSource;
@@ -94,6 +95,8 @@ public class VolumeControlService extends ProfileService {
* User Set Volume Setting means that remote keeps volume in its cache. */
@VisibleForTesting static final int VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK = 0x01;
+ private static final int GROUP_ID_INVALID = -1;
+
private static VolumeControlService sVolumeControlService;
@VisibleForTesting
@@ -268,16 +271,87 @@ public class VolumeControlService extends ProfileService {
return true;
}
+ private int getGroupId(BluetoothDevice device) {
+ if (device == null) {
+ return GROUP_ID_INVALID;
+ }
+
+ CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService();
+ if (csipClient != null) {
+ int groupId = csipClient.getGroupId(device, BluetoothUuid.CAP);
+ if (groupId != CSIS_GROUP_ID_INVALID) {
+ return groupId;
+ }
+ } else {
+ Log.w(TAG, "CSIP not available");
+ }
+
+ LeAudioService leAudioService = mFactory.getLeAudioService();
+ if (leAudioService != null) {
+ int groupId = leAudioService.getGroupId(device);
+ if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
+ return groupId;
+ }
+ } else {
+ Log.w(TAG, "leAudioService not available");
+ }
+
+ return GROUP_ID_INVALID;
+ }
+
+ private List<BluetoothDevice> getGroupDevices(int groupId) {
+ List<BluetoothDevice> result = new ArrayList<>();
+
+ if (groupId == GROUP_ID_INVALID) {
+ return result;
+ }
+
+ CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService();
+ if (csipClient != null) {
+ result = csipClient.getGroupDevicesOrdered(groupId);
+ if (!result.isEmpty()) {
+ return result;
+ }
+ } else {
+ Log.w(TAG, "CSIP not available");
+ }
+
+ LeAudioService leAudioService = mFactory.getLeAudioService();
+ if (leAudioService != null) {
+ result = leAudioService.getGroupDevices(groupId);
+ if (!result.isEmpty()) {
+ return result;
+ }
+ } else {
+ Log.w(TAG, "leAudioService not available");
+ }
+
+ return result;
+ }
+
public List<BluetoothDevice> getConnectedDevices() {
+ List<BluetoothDevice> devices = new ArrayList<>();
synchronized (mStateMachines) {
- List<BluetoothDevice> devices = new ArrayList<>();
for (VolumeControlStateMachine sm : mStateMachines.values()) {
if (sm.isConnected()) {
devices.add(sm.getDevice());
}
}
- return devices;
}
+ return devices;
+ }
+
+ private List<BluetoothDevice> getConnectedDevices(int groupId) {
+ List<BluetoothDevice> devices = new ArrayList<>();
+ synchronized (mStateMachines) {
+ for (BluetoothDevice dev : getGroupDevices(groupId)) {
+ VolumeControlStateMachine sm = mStateMachines.get(dev);
+ if (sm != null && sm.isConnected()) {
+ devices.add(dev);
+ }
+ }
+ }
+ return devices;
}
/**
@@ -460,15 +534,14 @@ public class VolumeControlService extends ProfileService {
TAG,
"setDeviceVolume: " + device + ", volume: " + volume + ", isGroupOp: " + isGroupOp);
- LeAudioService leAudioService = mFactory.getLeAudioService();
- if (leAudioService == null) {
- Log.e(TAG, "leAudioService not available");
+ if (volume < 0) {
+ Log.w(TAG, "Tried to set invalid volume " + volume + ". Ignored.");
return;
}
if (isGroupOp) {
- int groupId = leAudioService.getGroupId(device);
- if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) {
+ int groupId = getGroupId(device);
+ if (groupId == GROUP_ID_INVALID) {
Log.e(TAG, "Device not a part of a group");
return;
}
@@ -482,6 +555,8 @@ public class VolumeControlService extends ProfileService {
}
public void setGroupVolume(int groupId, int volume) {
+ Log.d(TAG, "setGroupVolume: " + groupId + ", volume: " + volume);
+
if (volume < 0) {
Log.w(TAG, "Tried to set invalid volume " + volume + ". Ignored.");
return;
@@ -491,7 +566,7 @@ public class VolumeControlService extends ProfileService {
mNativeInterface.setGroupVolume(groupId, volume);
// We only receive the volume change and mute state needs to be acquired manually
- Boolean isGroupMute = mGroupMuteCache.getOrDefault(groupId, false);
+ Boolean isGroupMute = getGroupMute(groupId);
Boolean isStreamMute = mAudioManager.isStreamMute(getBluetoothContextualVolumeStream());
/* Note: AudioService keeps volume levels for each stream and for each device type,
@@ -523,8 +598,7 @@ public class VolumeControlService extends ProfileService {
}
public int getGroupVolume(int groupId) {
- return mGroupVolumeCache.getOrDefault(
- groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME);
+ return mGroupVolumeCache.getOrDefault(groupId, VOLUME_CONTROL_UNKNOWN_VOLUME);
}
/**
@@ -534,8 +608,7 @@ public class VolumeControlService extends ProfileService {
* @return the cached volume
*/
public int getDeviceVolume(BluetoothDevice device) {
- return mDeviceVolumeCache.getOrDefault(
- device, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME);
+ return mDeviceVolumeCache.getOrDefault(device, VOLUME_CONTROL_UNKNOWN_VOLUME);
}
/**
@@ -554,7 +627,7 @@ public class VolumeControlService extends ProfileService {
int groupVolume = getGroupVolume(groupId);
Boolean groupMute = getGroupMute(groupId);
- if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
+ if (groupVolume != VOLUME_CONTROL_UNKNOWN_VOLUME) {
/* Don't need to show volume when activating known device. */
updateGroupCacheAndAudioSystem(groupId, groupVolume, groupMute, /* showInUI*/ false);
}
@@ -658,37 +731,24 @@ public class VolumeControlService extends ProfileService {
if (sm == null) {
return;
}
- if (sm.getConnectionState() != STATE_CONNECTED) {
+ if (!sm.isConnected()) {
return;
}
}
- // Correct the volume level only if device was already reported as connected.
- boolean can_change_volume = false;
- synchronized (mStateMachines) {
- VolumeControlStateMachine sm = mStateMachines.get(device);
- if (sm != null) {
- can_change_volume = (sm.getConnectionState() == STATE_CONNECTED);
- }
+ // If group volume has already changed, the new group member should set it
+ Integer groupVolume = getGroupVolume(groupId);
+ if (groupVolume != VOLUME_CONTROL_UNKNOWN_VOLUME) {
+ Log.i(TAG, "Setting value:" + groupVolume + " to " + device);
+ mNativeInterface.setVolume(device, groupVolume);
}
- // If group volume has already changed, the new group member should set it
- if (can_change_volume) {
- Integer groupVolume =
- mGroupVolumeCache.getOrDefault(
- groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME);
- if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
- Log.i(TAG, "Setting value:" + groupVolume + " to " + device);
- mNativeInterface.setVolume(device, groupVolume);
- }
-
- Boolean isGroupMuted = mGroupMuteCache.getOrDefault(groupId, false);
- Log.i(TAG, "Setting mute:" + isGroupMuted + " to " + device);
- if (isGroupMuted) {
- mNativeInterface.mute(device);
- } else {
- mNativeInterface.unmute(device);
- }
+ Boolean isGroupMuted = getGroupMute(groupId);
+ Log.i(TAG, "Setting mute:" + isGroupMuted + " to " + device);
+ if (isGroupMuted) {
+ mNativeInterface.mute(device);
+ } else {
+ mNativeInterface.unmute(device);
}
}
@@ -704,14 +764,18 @@ public class VolumeControlService extends ProfileService {
+ ", showInUI"
+ showInUI);
+ if (volume < 0) {
+ Log.w(TAG, "Tried to update invalid volume " + volume + ". Ignored.");
+ return;
+ }
+
mGroupVolumeCache.put(groupId, volume);
mGroupMuteCache.put(groupId, mute);
LeAudioService leAudioService = mFactory.getLeAudioService();
if (leAudioService != null) {
int currentlyActiveGroupId = leAudioService.getActiveGroupId();
- if (currentlyActiveGroupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID
- || groupId != currentlyActiveGroupId) {
+ if (currentlyActiveGroupId == GROUP_ID_INVALID || groupId != currentlyActiveGroupId) {
if (!Flags.leaudioBroadcastVolumeControlPrimaryGroupOnly()) {
Log.i(
TAG,
@@ -722,7 +786,7 @@ public class VolumeControlService extends ProfileService {
BassClientService bassClientService = mFactory.getBassClientService();
if (bassClientService == null
|| bassClientService.getSyncedBroadcastSinks().stream()
- .map(dev -> leAudioService.getGroupId(dev))
+ .map(dev -> getGroupId(dev))
.noneMatch(
id -> id == groupId && leAudioService.isPrimaryGroup(id))) {
Log.i(
@@ -766,16 +830,10 @@ public class VolumeControlService extends ProfileService {
int flags,
boolean mute,
boolean isAutonomous) {
- if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) {
- LeAudioService leAudioService = mFactory.getLeAudioService();
- if (leAudioService == null) {
- Log.e(TAG, "leAudioService not available");
- return;
- }
- groupId = leAudioService.getGroupId(device);
+ if (groupId == GROUP_ID_INVALID) {
+ groupId = getGroupId(device);
}
-
- if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) {
+ if (groupId == GROUP_ID_INVALID) {
Log.e(TAG, "Device not a part of the group");
return;
}
@@ -788,7 +846,8 @@ public class VolumeControlService extends ProfileService {
TAG,
("Initial volume set after connect, volume: " + volume)
+ (", mute: " + mute)
- + (", flags: " + flags));
+ + (", flags: " + flags)
+ + (", device: " + device));
/* We are here, because system has just started and LeAudio device is connected. If
* remote device has User Persistent flag set, Android sets the volume to local cache
* and to the audio system if not already streaming to other devices.
@@ -797,37 +856,36 @@ public class VolumeControlService extends ProfileService {
* Note, to match BR/EDR behavior, don't show volume change in UI here
*/
if (((flags & VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK) == 0x01)
- && (getConnectedDevices().size() == 1)) {
+ && (getConnectedDevices(groupId).size() == 1)) {
+ Log.i(TAG, "Setting device: " + device + " volume: " + volume + " to the system");
updateGroupCacheAndAudioSystem(groupId, volume, mute, false);
return;
}
// Reset flag is used
- if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
- Log.i(TAG, "Setting volume: " + groupVolume + " to the group: " + groupId);
+ if (groupVolume != VOLUME_CONTROL_UNKNOWN_VOLUME) {
+ Log.i(TAG, "Setting group volume: " + groupVolume + " to the device: " + device);
setGroupVolume(groupId, groupVolume);
} else {
- int vol = getBleVolumeFromCurrentStream();
- Log.i(TAG, "Setting system volume: " + vol + " to the group: " + groupId);
- setGroupVolume(groupId, getBleVolumeFromCurrentStream());
+ int systemVolume = getBleVolumeFromCurrentStream();
+ Log.i(TAG, "Setting system volume: " + systemVolume + " to the group: " + groupId);
+ setGroupVolume(groupId, systemVolume);
}
return;
}
- Log.i(TAG, "handleVolumeControlChanged: " + device + "; volume: " + volume);
+ Log.i(
+ TAG,
+ "handleVolumeControlChanged: "
+ + ("device: " + device)
+ + (", groupId: " + groupId)
+ + (", volume: " + volume));
if (device == null) {
// notify group devices volume changed
- LeAudioService leAudioService = mFactory.getLeAudioService();
- if (leAudioService != null) {
- synchronized (mCallbacks) {
- notifyDevicesVolumeChanged(
- mCallbacks,
- leAudioService.getGroupDevices(groupId),
- Optional.of(volume));
- }
- } else {
- Log.w(TAG, "leAudioService not available");
+ synchronized (mCallbacks) {
+ notifyDevicesVolumeChanged(
+ mCallbacks, getGroupDevices(groupId), Optional.of(volume));
}
} else {
// notify device volume changed
@@ -854,7 +912,7 @@ public class VolumeControlService extends ProfileService {
synchronized (mStateMachines) {
VolumeControlStateMachine sm = mStateMachines.get(device);
if (sm != null) {
- can_change_volume = (sm.getConnectionState() == STATE_CONNECTED);
+ can_change_volume = sm.isConnected();
}
}
@@ -895,7 +953,7 @@ public class VolumeControlService extends ProfileService {
volume = 0;
}
- if (volume == IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) return -1;
+ if (volume == VOLUME_CONTROL_UNKNOWN_VOLUME) return -1;
return getAudioDeviceVolume(getBluetoothContextualVolumeStream(), volume);
}
@@ -911,7 +969,7 @@ public class VolumeControlService extends ProfileService {
int getBluetoothContextualVolumeStream() {
int mode = mAudioManager.getMode();
- Log.d(TAG, "Volume mode: " + mode + "0: normal, 1: ring, 2,3: call");
+ Log.d(TAG, "Volume mode:" + mode + "; Description: 0:normal, 1:ring, 2,3:call");
return switch (mode) {
case AudioManager.MODE_IN_CALL, AudioManager.MODE_IN_COMMUNICATION -> {
@@ -981,7 +1039,7 @@ public class VolumeControlService extends ProfileService {
try {
mCallbacks.getBroadcastItem(i).onVolumeOffsetChanged(device, id, value);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mCallbacks.finishBroadcast();
@@ -1006,7 +1064,7 @@ public class VolumeControlService extends ProfileService {
.getBroadcastItem(i)
.onVolumeOffsetAudioLocationChanged(device, id, location);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mCallbacks.finishBroadcast();
@@ -1032,7 +1090,7 @@ public class VolumeControlService extends ProfileService {
.getBroadcastItem(i)
.onVolumeOffsetAudioDescriptionChanged(device, id, description);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
mCallbacks.finishBroadcast();
@@ -1313,37 +1371,23 @@ public class VolumeControlService extends ProfileService {
return;
}
- LeAudioService leAudioService = mFactory.getLeAudioService();
- if (leAudioService == null) {
- Log.e(TAG, "leAudioService not available");
- return;
- }
-
for (BluetoothDevice dev : devices) {
- int cachedVolume = IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME;
- if (!volume.isPresent()) {
- int groupId = leAudioService.getGroupId(dev);
- if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) {
- Log.e(TAG, "Device not a part of a group");
- continue;
- }
- // if device volume is available, notify with device volume, otherwise group volume
- cachedVolume = getDeviceVolume(dev);
- if (cachedVolume == IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
- cachedVolume = getGroupVolume(groupId);
- }
- }
- int broadcastVolume = cachedVolume;
+ int broadcastVolume = VOLUME_CONTROL_UNKNOWN_VOLUME;
if (volume.isPresent()) {
broadcastVolume = volume.get();
mDeviceVolumeCache.put(dev, broadcastVolume);
+ } else {
+ broadcastVolume = getDeviceVolume(dev);
+ if (broadcastVolume == VOLUME_CONTROL_UNKNOWN_VOLUME) {
+ broadcastVolume = getGroupVolume(getGroupId(dev));
+ }
}
int n = callbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
callbacks.getBroadcastItem(i).onDeviceVolumeChanged(dev, broadcastVolume);
} catch (RemoteException e) {
- continue;
+ // Ignore Exception
}
}
callbacks.finishBroadcast();
@@ -1432,29 +1476,19 @@ public class VolumeControlService extends ProfileService {
}
} else if (toState == STATE_CONNECTED) {
// Restore the group volume if it was changed while the device was not yet connected.
- CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService();
- if (csipClient != null) {
- Integer groupId = csipClient.getGroupId(device, BluetoothUuid.CAP);
- if (groupId != IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID) {
- Integer groupVolume =
- mGroupVolumeCache.getOrDefault(
- groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME);
- if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
- mNativeInterface.setVolume(device, groupVolume);
- }
+ Integer groupId = getGroupId(device);
+ if (groupId != GROUP_ID_INVALID) {
+ Integer groupVolume = getGroupVolume(groupId);
+ if (groupVolume != VOLUME_CONTROL_UNKNOWN_VOLUME) {
+ mNativeInterface.setVolume(device, groupVolume);
+ }
- Boolean groupMute = mGroupMuteCache.getOrDefault(groupId, false);
- if (groupMute) {
- mNativeInterface.mute(device);
- } else {
- mNativeInterface.unmute(device);
- }
+ Boolean groupMute = getGroupMute(groupId);
+ if (groupMute) {
+ mNativeInterface.mute(device);
+ } else {
+ mNativeInterface.unmute(device);
}
- } else {
- /* It could happen when Bluetooth is stopping while VC is getting
- * connection event
- */
- Log.w(TAG, "CSIP is not available");
}
}
mAdapterService.handleProfileConnectionStateChange(
@@ -1982,7 +2016,6 @@ public class VolumeControlService extends ProfileService {
}
for (Map.Entry<Integer, Integer> entry : mGroupVolumeCache.entrySet()) {
- Boolean isMute = mGroupMuteCache.getOrDefault(entry.getKey(), false);
ProfileService.println(
sb,
" GroupId: "
@@ -1990,7 +2023,7 @@ public class VolumeControlService extends ProfileService {
+ " volume: "
+ entry.getValue()
+ ", mute: "
- + isMute);
+ + getGroupMute(entry.getKey()));
}
}
}
diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java b/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java
index 71f520cbd9..184dbb8191 100644
--- a/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java
+++ b/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java
@@ -158,7 +158,7 @@ class VolumeControlStateMachine extends StateMachine {
processConnectionEvent(event.valueInt1);
}
default -> {
- Log.e(TAG, "Disconnected: forwarding stack event: " + event);
+ Log.d(TAG, "Disconnected: forwarding stack event: " + event);
mService.handleStackEvent(event);
}
}
@@ -270,7 +270,7 @@ class VolumeControlStateMachine extends StateMachine {
deferMessage(message);
}
default -> {
- Log.e(TAG, "Connecting: forwarding stack event: " + event);
+ Log.d(TAG, "Connecting: forwarding stack event: " + event);
mService.handleStackEvent(event);
}
}
@@ -366,7 +366,7 @@ class VolumeControlStateMachine extends StateMachine {
processConnectionEvent(event.valueInt1);
}
default -> {
- Log.e(TAG, "Disconnecting: forwarding stack event: " + event);
+ Log.d(TAG, "Disconnecting: forwarding stack event: " + event);
mService.handleStackEvent(event);
}
}
@@ -465,7 +465,7 @@ class VolumeControlStateMachine extends StateMachine {
processConnectionEvent(event.valueInt1);
}
default -> {
- Log.e(TAG, "Connected: forwarding stack event: " + event);
+ Log.d(TAG, "Connected: forwarding stack event: " + event);
mService.handleStackEvent(event);
}
}
diff --git a/android/app/tests/unit/Android.bp b/android/app/tests/unit/Android.bp
index f7f7a3dfc2..346c57fffa 100644
--- a/android/app/tests/unit/Android.bp
+++ b/android/app/tests/unit/Android.bp
@@ -55,9 +55,10 @@ java_defaults {
platform_apis: true,
test_suites: [
- "automotive-tests",
+ "automotive-general-tests",
"general-tests",
"mts-bluetooth",
+ "mts-bt",
],
instrumentation_for: "Bluetooth",
diff --git a/android/app/tests/unit/src/com/android/bluetooth/FileSystemWriteTest.java b/android/app/tests/unit/src/com/android/bluetooth/FileSystemWriteTest.java
index d04d2c2026..4f2b921d7c 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/FileSystemWriteTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/FileSystemWriteTest.java
@@ -15,10 +15,11 @@
*/
package com.android.bluetooth;
+import static com.google.common.truth.Truth.assertThat;
+
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,35 +31,23 @@ import java.io.IOException;
@RunWith(AndroidJUnit4.class)
public class FileSystemWriteTest {
@Test
- public void testBluetoothDirWrite() {
- try {
+ public void testBluetoothDirWrite() throws IOException {
File file = new File("/data/misc/bluetooth/test.file");
- Assert.assertTrue("File not created", file.createNewFile());
+ assertThat(file.createNewFile()).isTrue();
file.delete();
- } catch (IOException e) {
- Assert.fail("Exception creating file /data/misc/bluetooth/test.file: " + e);
- }
}
@Test
- public void testBluedroidDirWrite() {
- try {
+ public void testBluedroidDirWrite() throws IOException {
File file = new File("/data/misc/bluedroid/test.file");
- Assert.assertTrue("File not created", file.createNewFile());
+ assertThat(file.createNewFile()).isTrue();
file.delete();
- } catch (IOException e) {
- Assert.fail("Exception creating file /data/misc/bluedroid/test.file: " + e);
- }
}
@Test
- public void testBluetoothLogsDirWrite() {
- try {
+ public void testBluetoothLogsDirWrite() throws IOException {
File file = new File("/data/misc/bluetooth/logs/test.file");
- Assert.assertTrue("File not created", file.createNewFile());
+ assertThat(file.createNewFile()).isTrue();
file.delete();
- } catch (IOException e) {
- Assert.fail("Exception creating file /data/misc/bluetooth/logs/test.file: " + e);
- }
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java b/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java
index 4e7d23fe22..877df75ef2 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/TestUtils.java
@@ -15,6 +15,7 @@
*/
package com.android.bluetooth;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.eq;
@@ -93,11 +94,12 @@ public class TestUtils {
* mocked or spied
*/
public static void setAdapterService(AdapterService adapterService) {
- Assert.assertNull(
- "AdapterService.getAdapterService() must be null before setting another"
- + " AdapterService",
- AdapterService.getAdapterService());
- Assert.assertNotNull("Adapter service should not be null", adapterService);
+ assertWithMessage(
+ "AdapterService.getAdapterService() must be null before setting another"
+ + " AdapterService")
+ .that(AdapterService.getAdapterService())
+ .isNull();
+ assertThat(adapterService).isNotNull();
// We cannot mock AdapterService.getAdapterService() with Mockito.
// Hence we need to set AdapterService.sAdapterService field.
AdapterService.setAdapterService(adapterService);
@@ -115,7 +117,7 @@ public class TestUtils {
+ " supplied adapterService in this method",
adapterService,
AdapterService.getAdapterService());
- Assert.assertNotNull("Adapter service should not be null", adapterService);
+ assertThat(adapterService).isNotNull();
AdapterService.clearAdapterService(adapterService);
}
@@ -142,11 +144,11 @@ public class TestUtils {
* @return {@link BluetoothDevice} test device for the device ID
*/
public static BluetoothDevice getTestDevice(BluetoothAdapter bluetoothAdapter, int id) {
- Assert.assertTrue(id <= 0xFF);
- Assert.assertNotNull(bluetoothAdapter);
+ assertThat(id).isAtMost(0xFF);
+ assertThat(bluetoothAdapter).isNotNull();
BluetoothDevice testDevice =
bluetoothAdapter.getRemoteDevice(String.format("00:01:02:03:04:%02X", id));
- Assert.assertNotNull(testDevice);
+ assertThat(testDevice).isNotNull();
return testDevice;
}
@@ -173,7 +175,7 @@ public class TestUtils {
public static Intent waitForIntent(int timeoutMs, BlockingQueue<Intent> queue) {
try {
Intent intent = queue.poll(timeoutMs, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
return intent;
} catch (InterruptedException e) {
Assert.fail("Cannot obtain an Intent from the queue: " + e.getMessage());
@@ -186,17 +188,14 @@ public class TestUtils {
*
* @param timeoutMs the time (in milliseconds) to wait and verify no intent has been received
* @param queue the queue for the intent
- * @return the received intent. Should be null under normal circumstances
*/
- public static Intent waitForNoIntent(int timeoutMs, BlockingQueue<Intent> queue) {
+ public static void waitForNoIntent(int timeoutMs, BlockingQueue<Intent> queue) {
try {
Intent intent = queue.poll(timeoutMs, TimeUnit.MILLISECONDS);
- Assert.assertNull(intent);
- return intent;
+ assertThat(intent).isNull();
} catch (InterruptedException e) {
Assert.fail("Cannot obtain an Intent from the queue: " + e.getMessage());
}
- return null;
}
/**
@@ -279,7 +278,7 @@ public class TestUtils {
* <pre>{@code
* TestUtils.runOnMainSync(new Runnable() {
* public void run() {
- * Assert.assertTrue(mA2dpService.stop());
+ * assertThat(mA2dpService.stop()).isTrue();
* }
* });
* }</pre>
diff --git a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
index a398b2d6df..126c1559e9 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
@@ -110,7 +110,6 @@ public class A2dpServiceTest {
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
return FlagsParameterization.allCombinationsOf(
- Flags.FLAG_A2DP_SERVICE_LOOPER,
Flags.FLAG_A2DP_BROADCAST_CONNECTION_STATE_WHEN_TURNED_OFF);
}
@@ -155,19 +154,11 @@ public class A2dpServiceTest {
doReturn(new ParcelUuid[] {BluetoothUuid.A2DP_SINK})
.when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
-
- if (!Flags.a2dpServiceLooper()) {
- mLooper.startAutoDispatch();
- }
}
@After
public void tearDown() {
- if (Flags.a2dpServiceLooper()) {
- assertThat(mLooper.dispatchAll()).isEqualTo(0);
- } else {
- mLooper.stopAutoDispatchAndIgnoreExceptions();
- }
+ assertThat(mLooper.dispatchAll()).isEqualTo(0);
mA2dpService.stop();
}
@@ -333,7 +324,6 @@ public class A2dpServiceTest {
/** Test that an outgoing connection times out */
@Test
- @EnableFlags(Flags.FLAG_A2DP_SERVICE_LOOPER)
public void testOutgoingConnectTimeout() {
// Update the device priority so okToConnect() returns true
when(mDatabaseManager.getProfileConnectionPolicy(sTestDevice, BluetoothProfile.A2DP))
@@ -654,7 +644,6 @@ public class A2dpServiceTest {
* if the device is unbond.
*/
@Test
- @EnableFlags(Flags.FLAG_A2DP_SERVICE_LOOPER)
public void testDeleteStateMachineDisconnectEvents() {
// Update the device priority so okToConnect() returns true
when(mDatabaseManager.getProfileConnectionPolicy(sTestDevice, BluetoothProfile.A2DP))
@@ -1255,21 +1244,15 @@ public class A2dpServiceTest {
// Dispatch messages for the A2dpService looper, and validate
// that at least one message was handled.
private void dispatchAtLeastOneMessage() {
- if (Flags.a2dpServiceLooper()) {
- assertThat(mLooper.dispatchAll()).isGreaterThan(0);
- }
+ assertThat(mLooper.dispatchAll()).isGreaterThan(0);
}
// Validate that no messages are pending on the A2dpService looper.
private void dispatchNoMessages() {
- if (Flags.a2dpServiceLooper()) {
- assertThat(mLooper.dispatchAll()).isEqualTo(0);
- }
+ assertThat(mLooper.dispatchAll()).isEqualTo(0);
}
private void moveTimeForward(long millis) {
- if (Flags.a2dpServiceLooper()) {
- mLooper.moveTimeForward(millis);
- }
+ mLooper.moveTimeForward(millis);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java
index eae499a93f..09b188d55d 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java
@@ -27,6 +27,7 @@ import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
import static com.android.bluetooth.a2dp.A2dpStateMachine.MESSAGE_CONNECT;
+import static com.android.bluetooth.a2dp.A2dpStateMachine.MESSAGE_DISCONNECT;
import static com.android.bluetooth.a2dp.A2dpStateMachine.MESSAGE_STACK_EVENT;
import static com.google.common.truth.Truth.assertThat;
@@ -47,11 +48,14 @@ import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.test.TestLooper;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
+import com.android.bluetooth.flags.Flags;
import org.hamcrest.Matcher;
import org.hamcrest.core.AllOf;
@@ -72,6 +76,8 @@ import java.util.Arrays;
public class A2dpStateMachineTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock private A2dpService mService;
@Mock private A2dpNativeInterface mNativeInterface;
@@ -327,6 +333,23 @@ public class A2dpStateMachineTest {
mStateMachine.dump(new StringBuilder());
}
+ @Test
+ @EnableFlags(Flags.FLAG_A2DP_SM_IGNORE_CONNECT_EVENTS_IN_CONNECTING_STATE)
+ public void connectEventNeglectedWhileInConnectingState() {
+ sendAndDispatchMessage(MESSAGE_CONNECT, mDevice);
+ verifyConnectionStateIntent(STATE_CONNECTING, STATE_DISCONNECTED);
+ assertThat(mStateMachine.getCurrentState()).isInstanceOf(A2dpStateMachine.Connecting.class);
+
+ // Dispatch CONNECT event twice more
+ sendAndDispatchMessage(MESSAGE_CONNECT, mDevice);
+ sendAndDispatchMessage(MESSAGE_CONNECT, mDevice);
+ sendAndDispatchMessage(MESSAGE_DISCONNECT, mDevice);
+ verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING);
+ assertThat(mStateMachine.getCurrentState())
+ .isInstanceOf(A2dpStateMachine.Disconnected.class);
+ assertThat(mLooper.dispatchAll()).isEqualTo(0);
+ }
+
private void sendAndDispatchMessage(int what, Object obj) {
mStateMachine.sendMessage(what, obj);
mLooper.dispatchAll();
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 e2edf0903a..4b67658962 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
@@ -16,6 +16,8 @@
package com.android.bluetooth.audio_util;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.content.ContentResolver;
@@ -393,13 +395,13 @@ public class BrowserPlayerWrapperTest {
Assert.assertEquals(expected.isBrowsable(), item.isFolder);
if (item.isFolder) {
Folder folder = item.folder;
- Assert.assertNotNull(folder);
- Assert.assertFalse(folder.isPlayable);
+ assertThat(folder).isNotNull();
+ assertThat(folder.isPlayable).isFalse();
Assert.assertEquals(expected.getDescription().getMediaId(), folder.mediaId);
Assert.assertEquals(expected.getDescription().getTitle().toString(), folder.title);
} else {
Metadata song = item.song;
- Assert.assertNotNull(song);
+ assertThat(song).isNotNull();
Assert.assertEquals(expected.getDescription().getMediaId(), song.mediaId);
Assert.assertEquals(expected.getDescription().getTitle().toString(), song.title);
Assert.assertEquals(
@@ -407,11 +409,11 @@ public class BrowserPlayerWrapperTest {
Assert.assertEquals(
expected.getDescription().getDescription().toString(), song.album);
if (expected.getDescription().getIconBitmap() != null) {
- Assert.assertNotNull(song.image);
+ assertThat(song.image).isNotNull();
Bitmap expectedBitmap = expected.getDescription().getIconBitmap();
- Assert.assertTrue(expectedBitmap.sameAs(song.image.getImage()));
+ assertThat(expectedBitmap.sameAs(song.image.getImage())).isTrue();
} else if (expected.getDescription().getIconUri() != null) {
- Assert.assertTrue(mTestBitmap.sameAs(song.image.getImage()));
+ assertThat(mTestBitmap.sameAs(song.image.getImage())).isTrue();
} else {
Assert.assertEquals(null, song.image);
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerListTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerListTest.java
index 8308d0364a..c8e6a9f200 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerListTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerListTest.java
@@ -71,7 +71,6 @@ public class MediaPlayerListTest {
if (Looper.myLooper() == null) {
Looper.prepare();
}
- Assert.assertNotNull(Looper.myLooper());
AudioManager mockAudioManager = mock(AudioManager.class);
when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
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 f1e78940c6..2ffe3589d5 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
@@ -172,12 +172,10 @@ public class MediaPlayerWrapperTest {
*/
@Test
public void testNullControllerLooper() {
- MediaPlayerWrapper wrapper =
- MediaPlayerWrapperFactory.wrap(mMockContext, null, mThread.getLooper());
- Assert.assertNull(wrapper);
+ assertThat(MediaPlayerWrapperFactory.wrap(mMockContext, null, mThread.getLooper()))
+ .isNull();
- wrapper = MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, null);
- Assert.assertNull(wrapper);
+ assertThat(MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, null)).isNull();
}
/*
@@ -188,24 +186,24 @@ public class MediaPlayerWrapperTest {
public void testIsReady() {
MediaPlayerWrapper wrapper =
MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, mThread.getLooper());
- Assert.assertTrue(wrapper.isPlaybackStateReady());
- Assert.assertTrue(wrapper.isMetadataReady());
+ assertThat(wrapper.isPlaybackStateReady()).isTrue();
+ assertThat(wrapper.isMetadataReady()).isTrue();
// Test isPlaybackStateReady() is false when the playback state is null
doReturn(null).when(mMockController).getPlaybackState();
- Assert.assertFalse(wrapper.isPlaybackStateReady());
+ assertThat(wrapper.isPlaybackStateReady()).isFalse();
// Restore the old playback state
doReturn(mTestState.build()).when(mMockController).getPlaybackState();
- Assert.assertTrue(wrapper.isPlaybackStateReady());
+ assertThat(wrapper.isPlaybackStateReady()).isTrue();
// Test isMetadataReady() is false when the metadata is null
doReturn(null).when(mMockController).getMetadata();
- Assert.assertFalse(wrapper.isMetadataReady());
+ assertThat(wrapper.isMetadataReady()).isFalse();
// Restore the old metadata
doReturn(mTestMetadata.build()).when(mMockController).getMetadata();
- Assert.assertTrue(wrapper.isMetadataReady());
+ assertThat(wrapper.isMetadataReady()).isTrue();
}
/*
@@ -217,8 +215,8 @@ public class MediaPlayerWrapperTest {
// Create the wrapper object and register the looper with the timeout handler
MediaPlayerWrapper wrapper =
MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, mThread.getLooper());
- Assert.assertTrue(wrapper.isPlaybackStateReady());
- Assert.assertTrue(wrapper.isMetadataReady());
+ assertThat(wrapper.isPlaybackStateReady()).isTrue();
+ assertThat(wrapper.isMetadataReady()).isTrue();
wrapper.registerCallback(mTestCbs);
// Create a new MediaController that has different metadata than the previous controller
@@ -296,7 +294,7 @@ public class MediaPlayerWrapperTest {
Assert.assertEquals("Returned Queue isn't empty", data.queue.size(), 0);
// Verify that there are no timeout messages pending and there were no timeouts
- Assert.assertFalse(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT));
+ assertThat(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT)).isFalse();
verify(mFailHandler, never()).onTerribleFailure(any(), any(), anyBoolean());
}
@@ -345,7 +343,7 @@ public class MediaPlayerWrapperTest {
Assert.assertEquals("Returned Queue isn't empty", data.queue.size(), 0);
// Verify that there are no timeout messages pending and there were no timeouts
- Assert.assertFalse(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT));
+ assertThat(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT)).isFalse();
verify(mFailHandler, never()).onTerribleFailure(any(), any(), anyBoolean());
}
@@ -470,19 +468,16 @@ public class MediaPlayerWrapperTest {
MediaPlayerWrapperFactory.wrap(mMockContext, mMockController, mThread.getLooper());
doReturn(null).when(mMockController).getMetadata();
- Assert.assertFalse(
- Util.toMetadata(mMockContext, mTestMetadata.build())
- .duration
- .equals(wrapper.getCurrentQueue().get(0).duration));
+ assertThat(Util.toMetadata(mMockContext, mTestMetadata.build()).duration)
+ .isNotEqualTo(wrapper.getCurrentQueue().get(0).duration);
doReturn(mTestMetadata.build()).when(mMockController).getMetadata();
Assert.assertEquals(
Util.toMetadata(mMockContext, mTestMetadata.build()).duration,
wrapper.getCurrentQueue().get(0).duration);
// The MediaController Metadata should still not be equal to the queue
// as the track count is different and should not be overridden.
- Assert.assertFalse(
- Util.toMetadata(mMockContext, mTestMetadata.build())
- .equals(wrapper.getCurrentQueue().get(0)));
+ assertThat(Util.toMetadata(mMockContext, mTestMetadata.build()))
+ .isNotEqualTo(wrapper.getCurrentQueue().get(0));
}
/*
@@ -537,7 +532,7 @@ public class MediaPlayerWrapperTest {
controllerCallbacks.onPlaybackStateChanged(mTestState.build());
// Verify that there are no timeout messages pending and there were no timeouts
- Assert.assertFalse(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT));
+ assertThat(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT)).isFalse();
verify(mFailHandler, never()).onTerribleFailure(any(), any(), anyBoolean());
}
@@ -556,7 +551,7 @@ public class MediaPlayerWrapperTest {
// Ensure that everything was cleaned up
verify(mMockController).unregisterCallback(any());
- Assert.assertNull(wrapper.getTimeoutHandler());
+ assertThat(wrapper.getTimeoutHandler()).isNull();
}
/*
@@ -583,7 +578,7 @@ public class MediaPlayerWrapperTest {
verify(mTestCbs, never()).mediaUpdatedCallback(any());
// Verify that there are no timeout messages pending and there were no timeouts
- Assert.assertFalse(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT));
+ assertThat(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT)).isFalse();
verify(mFailHandler, never()).onTerribleFailure(any(), any(), anyBoolean());
}
@@ -642,7 +637,7 @@ public class MediaPlayerWrapperTest {
Util.toMetadataList(mMockContext, getQueueFromDescriptions(mTestQueue)));
// Verify that there are no timeout messages pending and there were no timeouts
- Assert.assertFalse(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT));
+ assertThat(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT)).isFalse();
verify(mFailHandler, never()).onTerribleFailure(any(), any(), anyBoolean());
}
@@ -771,7 +766,7 @@ public class MediaPlayerWrapperTest {
}
// Verify that there are no timeout messages pending and there were no timeouts
- Assert.assertFalse(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT));
+ assertThat(wrapper.getTimeoutHandler().hasMessages(MSG_TIMEOUT)).isFalse();
verify(mFailHandler, never()).onTerribleFailure(any(), any(), anyBoolean());
}
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 7a882a2627..5ba6e0f4e5 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
@@ -42,7 +42,6 @@ import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -261,7 +260,7 @@ public class MetadataTest {
assertThat(metadata.numTracks).isEqualTo(numTracks);
assertThat(metadata.genre).isEqualTo(genre);
assertThat(metadata.duration).isEqualTo(duration);
- Assert.assertTrue(Image.sameAs(metadata.image, image));
+ assertThat(Image.sameAs(metadata.image, image)).isTrue();
}
/** Make sure the media ID we set is transferred to Metadata object we build */
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcp/AvrcpTargetServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcp/AvrcpTargetServiceTest.java
index 1713b7a29f..20bc574fd9 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcp/AvrcpTargetServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcp/AvrcpTargetServiceTest.java
@@ -18,17 +18,41 @@ package com.android.bluetooth.avrcp;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.media.AudioDeviceCallback;
+import android.media.AudioManager;
+import android.media.session.MediaSessionManager;
import android.net.Uri;
+import android.os.UserManager;
+import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.bluetooth.TestUtils;
import com.android.bluetooth.audio_util.Image;
import com.android.bluetooth.audio_util.Metadata;
+import com.android.bluetooth.btservice.AdapterService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@@ -37,8 +61,63 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class AvrcpTargetServiceTest {
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ private @Mock AdapterService mMockAdapterService;
+ private @Mock AudioManager mMockAudioManager;
+ private @Mock AvrcpNativeInterface mMockNativeInterface;
+ private @Mock UserManager mMockUserManager;
+ private @Mock Resources mMockResources;
+ private @Mock SharedPreferences mMockSharedPreferences;
+ private @Mock SharedPreferences.Editor mMockSharedPreferencesEditor;
+
+ private @Captor ArgumentCaptor<AudioDeviceCallback> mAudioDeviceCb;
+
+ private MediaSessionManager mMediaSessionManager;
+ private TestLooper mLooper;
+
private static final String TEST_DATA = "-1";
+ @Before
+ public void setUp() throws Exception {
+ mLooper = new TestLooper();
+ mLooper.startAutoDispatch();
+
+ doReturn(mMockAudioManager)
+ .when(mMockAdapterService)
+ .getSystemService(Context.AUDIO_SERVICE);
+ doReturn(Context.AUDIO_SERVICE)
+ .when(mMockAdapterService)
+ .getSystemServiceName(AudioManager.class);
+
+ mMediaSessionManager =
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .getSystemService(MediaSessionManager.class);
+ TestUtils.mockGetSystemService(
+ mMockAdapterService,
+ Context.MEDIA_SESSION_SERVICE,
+ MediaSessionManager.class,
+ mMediaSessionManager);
+
+ doReturn(mLooper.getNewExecutor()).when(mMockAdapterService).getMainExecutor();
+
+ doReturn(mMockAdapterService).when(mMockAdapterService).getApplicationContext();
+ TestUtils.mockGetSystemService(
+ mMockAdapterService, Context.USER_SERVICE, UserManager.class, mMockUserManager);
+ doReturn(mMockResources).when(mMockAdapterService).getResources();
+
+ doReturn(mMockSharedPreferencesEditor).when(mMockSharedPreferences).edit();
+ doReturn(mMockSharedPreferences)
+ .when(mMockAdapterService)
+ .getSharedPreferences(anyString(), anyInt());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mLooper.stopAutoDispatchAndIgnoreExceptions();
+ }
+
@Test
public void testQueueUpdateData() {
List<Metadata> firstQueue = new ArrayList<Metadata>();
@@ -75,4 +154,27 @@ public class AvrcpTargetServiceTest {
Metadata.Builder builder = new Metadata.Builder();
return builder.useDefaults().build();
}
+
+ @Test
+ public void testServiceInstance() {
+ AvrcpVolumeManager volumeManager =
+ new AvrcpVolumeManager(
+ mMockAdapterService, mMockAudioManager, mMockNativeInterface);
+ AvrcpTargetService service =
+ new AvrcpTargetService(
+ mMockAdapterService,
+ mMockAudioManager,
+ mMockNativeInterface,
+ volumeManager,
+ mLooper.getLooper());
+
+ service.start();
+ verify(mMockAudioManager)
+ .registerAudioDeviceCallback(mAudioDeviceCb.capture(), anyObject());
+
+ service.stop();
+ service.cleanup();
+ assertThat(mAudioDeviceCb.getValue()).isNotNull();
+ verify(mMockAudioManager).unregisterAudioDeviceCallback(mAudioDeviceCb.getValue());
+ }
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
index dbe35e1660..03a05875b2 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
@@ -105,7 +105,6 @@ public class AvrcpControllerStateMachineTest {
if (Looper.myLooper() == null) {
Looper.prepare();
}
- Assert.assertNotNull(Looper.myLooper());
// Set a mock Adapter Service for profile state change notifications
TestUtils.setAdapterService(mAdapterService);
@@ -328,7 +327,7 @@ public class AvrcpControllerStateMachineTest {
// Make sure its set by re grabbing the node and checking its contents are cached
nowPlaying = mAvrcpStateMachine.findNode("NOW_PLAYING");
- Assert.assertTrue(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isTrue();
assertNowPlayingList(nowPlayingList);
}
@@ -410,7 +409,7 @@ public class AvrcpControllerStateMachineTest {
int numBroadcastsSent = setUpConnectedState(true, false);
MediaControllerCompat.TransportControls transportControls =
BluetoothMediaBrowserService.getTransportControls();
- Assert.assertNotNull(transportControls);
+ assertThat(transportControls).isNotNull();
Assert.assertEquals(
PlaybackStateCompat.STATE_NONE,
BluetoothMediaBrowserService.getPlaybackState().getState());
@@ -487,7 +486,7 @@ public class AvrcpControllerStateMachineTest {
public void testDump() {
StringBuilder sb = new StringBuilder();
mAvrcpStateMachine.dump(sb);
- Assert.assertNotNull(sb.toString());
+ assertThat(sb.toString()).isNotNull();
}
/** Test media browser play command */
@@ -755,7 +754,7 @@ public class AvrcpControllerStateMachineTest {
AvrcpControllerStateMachine.MESSAGE_PROCESS_AVAILABLE_PLAYER_CHANGED);
// Verify we've uncached our browse root and made the call to fetch new players
- Assert.assertFalse(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached());
+ assertThat(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached()).isFalse();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
.getPlayerList(eq(mTestAddress), eq(0), eq(19));
}
@@ -784,7 +783,7 @@ public class AvrcpControllerStateMachineTest {
AvrcpControllerStateMachine.MESSAGE_PROCESS_AVAILABLE_PLAYER_CHANGED);
// Verify we've uncached our browse root and made the call to fetch new players
- Assert.assertFalse(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached());
+ assertThat(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached()).isFalse();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
.getPlayerList(eq(mTestAddress), eq(0), eq(19));
@@ -804,12 +803,12 @@ public class AvrcpControllerStateMachineTest {
// Verify we processed the first players properly. Note the addressed player should always
// be in the available player set.
- Assert.assertTrue(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached());
+ assertThat(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached()).isTrue();
SparseArray<AvrcpPlayer> players = mAvrcpStateMachine.getAvailablePlayers();
- Assert.assertTrue(players.contains(mAvrcpStateMachine.getAddressedPlayerId()));
+ assertThat(players.contains(mAvrcpStateMachine.getAddressedPlayerId())).isTrue();
Assert.assertEquals(testPlayers.size(), players.size());
for (AvrcpPlayer player : testPlayers) {
- Assert.assertTrue(players.contains(player.getId()));
+ assertThat(players.contains(player.getId())).isTrue();
}
// Verify we request metadata, playback state and now playing list
@@ -835,7 +834,7 @@ public class AvrcpControllerStateMachineTest {
AvrcpControllerStateMachine.MESSAGE_PROCESS_AVAILABLE_PLAYER_CHANGED);
// Verify we've uncached our browse root and made the call to fetch new players
- Assert.assertFalse(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached());
+ assertThat(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached()).isFalse();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
.getPlayerList(eq(mTestAddress), eq(0), eq(19));
@@ -856,12 +855,12 @@ public class AvrcpControllerStateMachineTest {
// Verify we processed the players properly. Note the addressed player is currently the
// default player and is not in the available player set sent. This means we'll have an
// extra player at ID -1.
- Assert.assertTrue(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached());
+ assertThat(mAvrcpStateMachine.mBrowseTree.mRootNode.isCached()).isTrue();
SparseArray<AvrcpPlayer> players = mAvrcpStateMachine.getAvailablePlayers();
- Assert.assertTrue(players.contains(mAvrcpStateMachine.getAddressedPlayerId()));
+ assertThat(players.contains(mAvrcpStateMachine.getAddressedPlayerId())).isTrue();
Assert.assertEquals(testPlayers.size() + 1, players.size());
for (AvrcpPlayer player : testPlayers) {
- Assert.assertTrue(players.contains(player.getId()));
+ assertThat(players.contains(player.getId())).isTrue();
}
// Verify we do not request metadata, playback state and now playing list because we're
@@ -916,7 +915,7 @@ public class AvrcpControllerStateMachineTest {
// The addressed player should always be in the available player set
Assert.assertEquals(2, mAvrcpStateMachine.getAddressedPlayerId());
SparseArray<AvrcpPlayer> players = mAvrcpStateMachine.getAvailablePlayers();
- Assert.assertTrue(players.contains(mAvrcpStateMachine.getAddressedPlayerId()));
+ assertThat(players.contains(mAvrcpStateMachine.getAddressedPlayerId())).isTrue();
// Make sure the Now Playing list is now cleared
assertNowPlayingList(new ArrayList<AvrcpItem>());
@@ -1194,7 +1193,7 @@ public class AvrcpControllerStateMachineTest {
public void testPlaybackWhilePlayingState() {
when(mA2dpSinkService.getFocusState()).thenReturn(AudioManager.AUDIOFOCUS_GAIN);
setUpConnectedState(true, true);
- Assert.assertTrue(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isTrue();
mAvrcpStateMachine.sendMessage(
AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,
PlaybackStateCompat.STATE_PLAYING);
@@ -1210,14 +1209,14 @@ public class AvrcpControllerStateMachineTest {
/** Test that isActive() reports the proper value when we're active */
@Test
public void testIsActive_deviceActive() {
- Assert.assertTrue(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isTrue();
}
/** Test that isActive() reports the proper value when we're inactive */
@Test
public void testIsActive_deviceInactive() {
setActiveDevice(null);
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
}
/** Test becoming active from the inactive state */
@@ -1225,12 +1224,12 @@ public class AvrcpControllerStateMachineTest {
public void testBecomeActive() {
// Note device starts as active in setUp() and state cascades come the CONNECTED state
setUpConnectedState(true, true);
- Assert.assertTrue(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isTrue();
// Make the device inactive
setActiveDevice(null);
TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
// Change device state while inactive
AvrcpItem track = makeTrack("title", "artist", "album", 1, 10, "none", 10, null);
@@ -1247,16 +1246,16 @@ public class AvrcpControllerStateMachineTest {
// Make device active
setActiveDevice(mTestDevice);
TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
- Assert.assertTrue(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isTrue();
// See that state from BluetoothMediaBrowserService is updated
MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
- Assert.assertNotNull(session);
+ assertThat(session).isNotNull();
MediaControllerCompat controller = session.getController();
- Assert.assertNotNull(controller);
+ assertThat(controller).isNotNull();
MediaMetadataCompat metadata = controller.getMetadata();
- Assert.assertNotNull(metadata);
+ assertThat(metadata).isNotNull();
Assert.assertEquals("title", metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
Assert.assertEquals("artist", metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
Assert.assertEquals("album", metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
@@ -1266,12 +1265,12 @@ public class AvrcpControllerStateMachineTest {
Assert.assertEquals(10, metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
PlaybackStateCompat playbackState = controller.getPlaybackState();
- Assert.assertNotNull(playbackState);
+ assertThat(playbackState).isNotNull();
Assert.assertEquals(PlaybackStateCompat.STATE_PAUSED, playbackState.getState());
Assert.assertEquals(7, playbackState.getPosition());
List<MediaSessionCompat.QueueItem> queue = controller.getQueue();
- Assert.assertNotNull(queue);
+ assertThat(queue).isNotNull();
Assert.assertEquals(2, queue.size());
Assert.assertEquals("title", queue.get(0).getDescription().getTitle().toString());
Assert.assertEquals("title 2", queue.get(1).getDescription().getTitle().toString());
@@ -1282,7 +1281,7 @@ public class AvrcpControllerStateMachineTest {
public void testBecomeInactive() {
// Note device starts as active in setUp()
setUpConnectedState(true, true);
- Assert.assertTrue(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isTrue();
// Set the active device to something else, verify we're inactive and send a pause upon
// becoming inactive
@@ -1293,7 +1292,7 @@ public class AvrcpControllerStateMachineTest {
eq(mTestAddress),
eq(AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE),
eq(KEY_DOWN));
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
}
@Test
@@ -1318,12 +1317,12 @@ public class AvrcpControllerStateMachineTest {
// Verify track and playback state
MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
- Assert.assertNotNull(session);
+ assertThat(session).isNotNull();
MediaControllerCompat controller = session.getController();
- Assert.assertNotNull(controller);
+ assertThat(controller).isNotNull();
MediaMetadataCompat metadata = controller.getMetadata();
- Assert.assertNotNull(metadata);
+ assertThat(metadata).isNotNull();
Assert.assertEquals("Song 1", metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
Assert.assertEquals("artist", metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
Assert.assertEquals("album", metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
@@ -1333,7 +1332,7 @@ public class AvrcpControllerStateMachineTest {
Assert.assertEquals(10, metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
PlaybackStateCompat playbackState = controller.getPlaybackState();
- Assert.assertNotNull(playbackState);
+ assertThat(playbackState).isNotNull();
Assert.assertEquals(PlaybackStateCompat.STATE_PLAYING, playbackState.getState());
Assert.assertEquals(0, playbackState.getActiveQueueItemId());
@@ -1344,7 +1343,7 @@ public class AvrcpControllerStateMachineTest {
// Assert new track metadata and active queue item
metadata = controller.getMetadata();
- Assert.assertNotNull(metadata);
+ assertThat(metadata).isNotNull();
Assert.assertEquals("Song 2", metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
Assert.assertEquals("artist", metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
Assert.assertEquals("album", metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
@@ -1354,7 +1353,7 @@ public class AvrcpControllerStateMachineTest {
Assert.assertEquals(10, metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
playbackState = controller.getPlaybackState();
- Assert.assertNotNull(playbackState);
+ assertThat(playbackState).isNotNull();
Assert.assertEquals(PlaybackStateCompat.STATE_PLAYING, playbackState.getState());
Assert.assertEquals(1, playbackState.getActiveQueueItemId());
}
@@ -1368,7 +1367,7 @@ public class AvrcpControllerStateMachineTest {
// becoming inactive
setActiveDevice(null);
TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
// Change track while inactive
AvrcpItem track = makeTrack("title", "artist", "album", 1, 10, "none", 10, null);
@@ -1376,12 +1375,11 @@ public class AvrcpControllerStateMachineTest {
// Since we're not active, verify BluetoothMediaBrowserService does not have these values
MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
- Assert.assertNotNull(session);
+ assertThat(session).isNotNull();
MediaControllerCompat controller = session.getController();
- Assert.assertNotNull(controller);
+ assertThat(controller).isNotNull();
- MediaMetadataCompat metadata = controller.getMetadata();
- Assert.assertNull(metadata); // track starts as null and shouldn't change
+ assertThat(controller.getMetadata()).isNull(); // track starts as null and shouldn't change
}
/** Test receiving a playback status of playing when we're not the active device */
@@ -1392,7 +1390,7 @@ public class AvrcpControllerStateMachineTest {
// Set the active device to something else, verify we're inactive
setActiveDevice(null);
TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
clearInvocations(mAvrcpControllerService);
clearInvocations(mNativeInterface);
@@ -1420,7 +1418,7 @@ public class AvrcpControllerStateMachineTest {
// Set the active device to something else, verify we're inactive
setActiveDevice(null);
TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
clearInvocations(mAvrcpControllerService);
clearInvocations(mNativeInterface);
@@ -1429,12 +1427,12 @@ public class AvrcpControllerStateMachineTest {
// Since we're not active, verify BluetoothMediaBrowserService does not have these values
MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
- Assert.assertNotNull(session);
+ assertThat(session).isNotNull();
MediaControllerCompat controller = session.getController();
- Assert.assertNotNull(controller);
+ assertThat(controller).isNotNull();
PlaybackStateCompat playbackState = controller.getPlaybackState();
- Assert.assertNotNull(playbackState);
+ assertThat(playbackState).isNotNull();
Assert.assertEquals(0, playbackState.getPosition());
}
@@ -1447,7 +1445,7 @@ public class AvrcpControllerStateMachineTest {
// becoming inactive
setActiveDevice(null);
TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
- Assert.assertFalse(mAvrcpStateMachine.isActive());
+ assertThat(mAvrcpStateMachine.isActive()).isFalse();
// Change queue while inactive
List<AvrcpItem> nowPlayingList = new ArrayList<AvrcpItem>();
@@ -1461,12 +1459,11 @@ public class AvrcpControllerStateMachineTest {
// Since we're not active, verify BluetoothMediaBrowserService does not have these values
MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
- Assert.assertNotNull(session);
+ assertThat(session).isNotNull();
MediaControllerCompat controller = session.getController();
- Assert.assertNotNull(controller);
+ assertThat(controller).isNotNull();
- List<MediaSessionCompat.QueueItem> queue = controller.getQueue();
- Assert.assertNull(queue);
+ assertThat(controller.getQueue()).isNull();
}
/**
@@ -1773,7 +1770,7 @@ public class AvrcpControllerStateMachineTest {
// Make sure its set by re grabbing the node and checking its contents are cached
nowPlaying = mAvrcpStateMachine.findNode("NOW_PLAYING");
- Assert.assertTrue(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isTrue();
assertNowPlayingList(updatedNowPlayingList);
}
@@ -1833,7 +1830,7 @@ public class AvrcpControllerStateMachineTest {
// Make sure its set by re grabbing the node and checking its contents are cached
nowPlaying = mAvrcpStateMachine.findNode("NOW_PLAYING");
- Assert.assertTrue(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isTrue();
assertNowPlayingList(updatedNowPlayingList);
}
@@ -1901,7 +1898,7 @@ public class AvrcpControllerStateMachineTest {
// Make sure its set by re grabbing the node and checking its contents are cached
nowPlaying = mAvrcpStateMachine.findNode("NOW_PLAYING");
- Assert.assertTrue(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isTrue();
assertNowPlayingList(updatedNowPlayingList);
}
@@ -1966,7 +1963,7 @@ public class AvrcpControllerStateMachineTest {
// Make sure its set by re grabbing the node and checking its contents are cached
nowPlaying = mAvrcpStateMachine.findNode("NOW_PLAYING");
- Assert.assertTrue(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isTrue();
assertNowPlayingList(updatedNowPlayingList);
}
@@ -1993,7 +1990,7 @@ public class AvrcpControllerStateMachineTest {
// Request for new contents should be sent
verify(mNativeInterface).getNowPlayingList(eq(mTestAddress), eq(0), eq(19));
- Assert.assertFalse(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isFalse();
// Send timeout on our own instead of waiting 10 seconds
mAvrcpStateMachine.sendMessage(AvrcpControllerStateMachine.MESSAGE_INTERNAL_CMD_TIMEOUT);
@@ -2001,15 +1998,14 @@ public class AvrcpControllerStateMachineTest {
// Node should be set to cached and notified on
assertNowPlayingList(new ArrayList<AvrcpItem>());
- Assert.assertTrue(nowPlaying.isCached());
+ assertThat(nowPlaying.isCached()).isTrue();
// See that state from BluetoothMediaBrowserService is updated to null (i.e. empty)
MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
- Assert.assertNotNull(session);
+ assertThat(session).isNotNull();
MediaControllerCompat controller = session.getController();
- Assert.assertNotNull(controller);
- List<MediaSessionCompat.QueueItem> queue = controller.getQueue();
- Assert.assertNull(queue);
+ assertThat(controller).isNotNull();
+ assertThat(controller.getQueue()).isNull();
}
/**
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorageTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorageTest.java
index f11054f05c..6cf6bb466b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorageTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorageTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
@@ -83,32 +85,32 @@ public final class AvrcpCoverArtStorageTest {
private void assertImageSame(Bitmap expected, BluetoothDevice device, String handle) {
Bitmap image = mAvrcpCoverArtStorage.getImage(device, handle);
- Assert.assertTrue(expected.sameAs(image));
+ assertThat(expected.sameAs(image)).isTrue();
}
@Test
public void addNewImage_imageExists() {
Uri expectedUri = AvrcpCoverArtProvider.getImageUri(mDevice1, mHandle1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Uri uri = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
Assert.assertEquals(expectedUri, uri);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
}
@Test
public void addExistingImage_imageUpdated() {
Uri expectedUri = AvrcpCoverArtProvider.getImageUri(mDevice1, mHandle1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Uri uri = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
Assert.assertEquals(expectedUri, uri);
assertImageSame(mImage1, mDevice1, mHandle1);
uri = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage2);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
Assert.assertEquals(expectedUri, uri);
assertImageSame(mImage2, mDevice1, mHandle1);
}
@@ -117,16 +119,16 @@ public final class AvrcpCoverArtStorageTest {
public void addTwoImageSameDevice_bothExist() {
Uri expectedUri1 = AvrcpCoverArtProvider.getImageUri(mDevice1, mHandle1);
Uri expectedUri2 = AvrcpCoverArtProvider.getImageUri(mDevice1, mHandle2);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isFalse();
Uri uri1 = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
Uri uri2 = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle2, mImage2);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
Assert.assertEquals(expectedUri1, uri1);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isTrue();
Assert.assertEquals(expectedUri2, uri2);
}
@@ -134,51 +136,51 @@ public final class AvrcpCoverArtStorageTest {
public void addTwoImageDifferentDevices_bothExist() {
Uri expectedUri1 = AvrcpCoverArtProvider.getImageUri(mDevice1, mHandle1);
Uri expectedUri2 = AvrcpCoverArtProvider.getImageUri(mDevice2, mHandle1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1)).isFalse();
Uri uri1 = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
Uri uri2 = mAvrcpCoverArtStorage.addImage(mDevice2, mHandle1, mImage1);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
Assert.assertEquals(expectedUri1, uri1);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
Assert.assertEquals(expectedUri2, uri2);
}
@Test
public void addNullImage_imageNotAdded() {
Uri uri = mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, null);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Assert.assertEquals(null, uri);
}
@Test
public void addImageNullDevice_imageNotAdded() {
Uri uri = mAvrcpCoverArtStorage.addImage(null, mHandle1, mImage1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Assert.assertEquals(null, uri);
}
@Test
public void addImageNullHandle_imageNotAdded() {
Uri uri = mAvrcpCoverArtStorage.addImage(mDevice1, null, mImage1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Assert.assertEquals(null, uri);
}
@Test
public void addImageEmptyHandle_imageNotAdded() {
Uri uri = mAvrcpCoverArtStorage.addImage(mDevice1, "", mImage1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Assert.assertEquals(null, uri);
}
@Test
public void getImage_canGetImageFromStorage() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
assertImageSame(mImage1, mDevice1, mHandle1);
}
@@ -186,36 +188,36 @@ public final class AvrcpCoverArtStorageTest {
public void getImageSameHandleDifferentDevices_canGetImagesFromStorage() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
mAvrcpCoverArtStorage.addImage(mDevice2, mHandle1, mImage2);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1)).isTrue();
assertImageSame(mImage1, mDevice1, mHandle1);
assertImageSame(mImage2, mDevice2, mHandle1);
}
@Test
public void getImageThatDoesntExist_returnsNull() {
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Bitmap image = mAvrcpCoverArtStorage.getImage(mDevice1, mHandle1);
Assert.assertEquals(null, image);
}
@Test
public void getImageNullDevice_returnsNull() {
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Bitmap image = mAvrcpCoverArtStorage.getImage(null, mHandle1);
Assert.assertEquals(null, image);
}
@Test
public void getImageNullHandle_returnsNull() {
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Bitmap image = mAvrcpCoverArtStorage.getImage(mDevice1, null);
Assert.assertEquals(null, image);
}
@Test
public void getImageEmptyHandle_returnsNull() {
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
Bitmap image = mAvrcpCoverArtStorage.getImage(mDevice1, "");
Assert.assertEquals(null, image);
}
@@ -226,44 +228,44 @@ public final class AvrcpCoverArtStorageTest {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle2, mImage1);
mAvrcpCoverArtStorage.addImage(mDevice2, mHandle1, mImage1);
mAvrcpCoverArtStorage.removeImage(mDevice1, mHandle1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isTrue();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1)).isTrue();
}
@Test
public void removeNonExistentImage_nothingHappens() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
mAvrcpCoverArtStorage.removeImage(mDevice1, mHandle2);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
}
@Test
public void removeImageNullDevice_nothingHappens() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
mAvrcpCoverArtStorage.removeImage(null, mHandle1);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
}
@Test
public void removeImageNullHandle_nothingHappens() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
mAvrcpCoverArtStorage.removeImage(mDevice1, null);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
}
@Test
public void removeImageEmptyHandle_nothingHappens() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
mAvrcpCoverArtStorage.removeImage(mDevice1, "");
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
}
@Test
public void removeImageNullInputs_nothingHappens() {
mAvrcpCoverArtStorage.addImage(mDevice1, mHandle1, mImage1);
mAvrcpCoverArtStorage.removeImage(null, null);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
}
@Test
@@ -274,9 +276,9 @@ public final class AvrcpCoverArtStorageTest {
mAvrcpCoverArtStorage.removeImagesForDevice(mDevice1);
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1)).isTrue();
}
@Test
@@ -286,8 +288,8 @@ public final class AvrcpCoverArtStorageTest {
mAvrcpCoverArtStorage.removeImagesForDevice(mDevice2);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isTrue();
}
@Test
@@ -297,8 +299,8 @@ public final class AvrcpCoverArtStorageTest {
mAvrcpCoverArtStorage.removeImagesForDevice(null);
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertTrue(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isTrue();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isTrue();
}
@Test
@@ -308,8 +310,8 @@ public final class AvrcpCoverArtStorageTest {
mAvrcpCoverArtStorage.clear();
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isFalse();
}
@Test
@@ -321,10 +323,10 @@ public final class AvrcpCoverArtStorageTest {
mAvrcpCoverArtStorage.clear();
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1));
- Assert.assertFalse(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle2));
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice1, mHandle2)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle1)).isFalse();
+ assertThat(mAvrcpCoverArtStorage.doesImageExist(mDevice2, mHandle2)).isFalse();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpItemTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpItemTest.java
index 8df38adcde..7a296cd075 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpItemTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpItemTest.java
@@ -16,6 +16,9 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.net.Uri;
@@ -473,7 +476,7 @@ public final class AvrcpItemTest {
null, metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON));
Assert.assertEquals(null, metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ART));
Assert.assertEquals(null, metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART));
- Assert.assertFalse(metadata.containsKey(MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE));
+ assertThat(metadata.containsKey(MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE)).isFalse();
}
@Test
@@ -545,14 +548,14 @@ public final class AvrcpItemTest {
MediaItem mediaItem = item.toMediaItem();
MediaDescriptionCompat desc = mediaItem.getDescription();
- Assert.assertTrue(mediaItem.isPlayable());
- Assert.assertFalse(mediaItem.isBrowsable());
+ assertThat(mediaItem.isPlayable()).isTrue();
+ assertThat(mediaItem.isBrowsable()).isFalse();
Assert.assertEquals(UUID, mediaItem.getMediaId());
Assert.assertEquals(UUID, desc.getMediaId());
Assert.assertEquals(null, desc.getMediaUri());
Assert.assertEquals(title, desc.getTitle().toString());
- Assert.assertNull(desc.getSubtitle());
+ assertThat(desc.getSubtitle()).isNull();
Assert.assertEquals(uri, desc.getIconUri());
Assert.assertEquals(null, desc.getIconBitmap());
}
@@ -574,14 +577,14 @@ public final class AvrcpItemTest {
MediaItem mediaItem = item.toMediaItem();
MediaDescriptionCompat desc = mediaItem.getDescription();
- Assert.assertTrue(mediaItem.isPlayable());
- Assert.assertFalse(mediaItem.isBrowsable());
+ assertThat(mediaItem.isPlayable()).isTrue();
+ assertThat(mediaItem.isBrowsable()).isFalse();
Assert.assertEquals(UUID, mediaItem.getMediaId());
Assert.assertEquals(UUID, desc.getMediaId());
Assert.assertEquals(null, desc.getMediaUri());
Assert.assertEquals(displayName, desc.getTitle().toString());
- Assert.assertNull(desc.getSubtitle());
+ assertThat(desc.getSubtitle()).isNull();
Assert.assertEquals(uri, desc.getIconUri());
Assert.assertEquals(null, desc.getIconBitmap());
}
@@ -601,14 +604,14 @@ public final class AvrcpItemTest {
MediaItem mediaItem = item.toMediaItem();
MediaDescriptionCompat desc = mediaItem.getDescription();
- Assert.assertFalse(mediaItem.isPlayable());
- Assert.assertTrue(mediaItem.isBrowsable());
+ assertThat(mediaItem.isPlayable()).isFalse();
+ assertThat(mediaItem.isBrowsable()).isTrue();
Assert.assertEquals(UUID, mediaItem.getMediaId());
Assert.assertEquals(UUID, desc.getMediaId());
Assert.assertEquals(null, desc.getMediaUri());
Assert.assertEquals(title, desc.getTitle().toString());
- Assert.assertNull(desc.getSubtitle());
+ assertThat(desc.getSubtitle()).isNull();
Assert.assertEquals(uri, desc.getIconUri());
Assert.assertEquals(null, desc.getIconBitmap());
}
@@ -619,17 +622,18 @@ public final class AvrcpItemTest {
AvrcpItem item = builder.build();
- Assert.assertTrue(item.equals(item));
+ assertThat(item).isEqualTo(item);
}
@Test
+ @SuppressLint("TruthIncompatibleType") // That the point of this test
public void equals_withDifferentInstance() {
AvrcpItem.Builder builder = new AvrcpItem.Builder();
String notAvrcpItem = "notAvrcpItem";
AvrcpItem item = builder.build();
- Assert.assertFalse(item.equals(notAvrcpItem));
+ assertThat(item).isNotEqualTo(notAvrcpItem);
}
@Test
@@ -640,6 +644,6 @@ public final class AvrcpItemTest {
AvrcpItem item = builder.build();
AvrcpItem itemEqual = builderEqual.build();
- Assert.assertTrue(item.equals(itemEqual));
+ assertThat(item).isEqualTo(itemEqual);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipAttachmentFormatTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipAttachmentFormatTest.java
index 00b56abfa4..c4ae402379 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipAttachmentFormatTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipAttachmentFormatTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import android.annotation.SuppressLint;
import androidx.test.runner.AndroidJUnit4;
@@ -98,14 +100,14 @@ public class BipAttachmentFormatTest {
if (created != null) {
Assert.assertEquals(created, attachment.getCreatedDate().getTime());
- Assert.assertTrue(attachment.getCreatedDate().isUtc());
+ assertThat(attachment.getCreatedDate().isUtc()).isTrue();
} else {
Assert.assertEquals(null, attachment.getCreatedDate());
}
if (modified != null) {
Assert.assertEquals(modified, attachment.getModifiedDate().getTime());
- Assert.assertTrue(attachment.getModifiedDate().isUtc());
+ assertThat(attachment.getModifiedDate().isUtc()).isTrue();
} else {
Assert.assertEquals(null, attachment.getModifiedDate());
}
@@ -424,16 +426,17 @@ public class BipAttachmentFormatTest {
BipAttachmentFormat attachment =
new BipAttachmentFormat("text/plain", null, "thisisatextfile.txt", -1, null, null);
- Assert.assertTrue(attachment.equals(attachment));
+ assertThat(attachment).isEqualTo(attachment);
}
@Test
+ @SuppressLint("TruthIncompatibleType") // That the point of this test
public void testEquals_withDifferentClass() {
BipAttachmentFormat attachment =
new BipAttachmentFormat("text/plain", null, "thisisatextfile.txt", -1, null, null);
String notAttachment = "notAttachment";
- Assert.assertFalse(attachment.equals(notAttachment));
+ assertThat(attachment).isNotEqualTo(notAttachment);
}
@Test
@@ -443,6 +446,6 @@ public class BipAttachmentFormatTest {
BipAttachmentFormat attachmentEqual =
new BipAttachmentFormat("text/plain", null, "thisisatextfile.txt", -1, null, null);
- Assert.assertTrue(attachment.equals(attachmentEqual));
+ assertThat(attachment).isEqualTo(attachmentEqual);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipDatetimeTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipDatetimeTest.java
index 913f77fe36..33937d8741 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipDatetimeTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipDatetimeTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import android.annotation.SuppressLint;
import androidx.test.runner.AndroidJUnit4;
@@ -74,7 +76,7 @@ public class BipDatetimeTest {
private void testCreate(Date date, String dateStr) {
BipDateTime bipDate = new BipDateTime(date);
Assert.assertEquals(date, bipDate.getTime());
- Assert.assertTrue(bipDate.isUtc());
+ assertThat(bipDate.isUtc()).isTrue();
Assert.assertEquals(dateStr, bipDate.toString());
}
@@ -215,10 +217,11 @@ public class BipDatetimeTest {
BipDateTime bipDate = new BipDateTime(makeDate(1, 1, 2000, 6, 1, 15, utc));
- Assert.assertTrue(bipDate.equals(bipDate));
+ assertThat(bipDate).isEqualTo(bipDate);
}
@Test
+ @SuppressLint("TruthIncompatibleType") // That the point of this test
public void testEquals_withDifferentClass() {
TimeZone utc = TimeZone.getTimeZone("UTC");
utc.setRawOffset(0);
@@ -226,7 +229,7 @@ public class BipDatetimeTest {
BipDateTime bipDate = new BipDateTime(makeDate(1, 1, 2000, 6, 1, 15, utc));
String notBipDate = "notBipDate";
- Assert.assertFalse(bipDate.equals(notBipDate));
+ assertThat(bipDate).isNotEqualTo(notBipDate);
}
@Test
@@ -238,6 +241,6 @@ public class BipDatetimeTest {
BipDateTime bipDate = new BipDateTime(date);
BipDateTime bipDateEqual = new BipDateTime(date);
- Assert.assertTrue(bipDate.equals(bipDateEqual));
+ assertThat(bipDate).isEqualTo(bipDateEqual);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipEncodingTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipEncodingTest.java
index c0600a4c29..2ffb5a9870 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipEncodingTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipEncodingTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import androidx.test.runner.AndroidJUnit4;
import org.junit.Assert;
@@ -120,7 +122,7 @@ public class BipEncodingTest {
Assert.assertEquals(BipEncoding.USR_XXX, encoding.getType());
Assert.assertEquals("TEST-ENCODING", encoding.getProprietaryEncodingId());
Assert.assertEquals("USR-TEST-ENCODING", encoding.toString());
- Assert.assertFalse(encoding.isAndroidSupported());
+ assertThat(encoding.isAndroidSupported()).isFalse();
}
@Test
@@ -129,7 +131,7 @@ public class BipEncodingTest {
Assert.assertEquals(BipEncoding.USR_XXX, encoding.getType());
Assert.assertEquals("", encoding.getProprietaryEncodingId());
Assert.assertEquals("USR-", encoding.toString());
- Assert.assertFalse(encoding.isAndroidSupported());
+ assertThat(encoding.isAndroidSupported()).isFalse();
}
@Test(expected = ParseException.class)
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptorTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptorTest.java
index 658dca4eef..971ec50064 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptorTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageDescriptorTest.java
@@ -16,6 +16,10 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.SuppressLint;
+
import androidx.test.runner.AndroidJUnit4;
import org.junit.Assert;
@@ -242,17 +246,18 @@ public class BipImageDescriptorTest {
BipImageDescriptor descriptor = builder.build();
- Assert.assertTrue(descriptor.equals(descriptor));
+ assertThat(descriptor).isEqualTo(descriptor);
}
@Test
+ @SuppressLint("TruthIncompatibleType") // That the point of this test
public void testEquals_differentClass() {
BipImageDescriptor.Builder builder = new BipImageDescriptor.Builder();
BipImageDescriptor descriptor = builder.build();
String notDescriptor = "notDescriptor";
- Assert.assertFalse(descriptor.equals(notDescriptor));
+ assertThat(descriptor).isNotEqualTo(notDescriptor);
}
@Test
@@ -263,6 +268,6 @@ public class BipImageDescriptorTest {
BipImageDescriptor descriptor = builder.build();
BipImageDescriptor descriptorEqual = builderEqual.build();
- Assert.assertTrue(descriptor.equals(descriptorEqual));
+ assertThat(descriptor).isEqualTo(descriptorEqual);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormatTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormatTest.java
index 1eb5c4a5fe..9c8aec1b85 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormatTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageFormatTest.java
@@ -16,6 +16,10 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.SuppressLint;
+
import androidx.test.runner.AndroidJUnit4;
import org.junit.Assert;
@@ -312,10 +316,11 @@ public class BipImageFormatTest {
BipPixel.createFixed(1280, 1024),
-1);
- Assert.assertTrue(format.equals(format));
+ assertThat(format).isEqualTo(format);
}
@Test
+ @SuppressLint("TruthIncompatibleType") // That the point of this test
public void testEquals_withDifferentClass() {
BipImageFormat format =
BipImageFormat.createNative(
@@ -324,7 +329,7 @@ public class BipImageFormatTest {
-1);
String notFormat = "notFormat";
- Assert.assertFalse(format.equals(notFormat));
+ assertThat(format).isNotEqualTo(notFormat);
}
@Test
@@ -335,6 +340,6 @@ public class BipImageFormatTest {
BipImageFormat format = BipImageFormat.createNative(encoding, pixel, -1);
BipImageFormat formatEqual = BipImageFormat.createNative(encoding, pixel, -1);
- Assert.assertTrue(format.equals(formatEqual));
+ assertThat(format).isEqualTo(formatEqual);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImagePropertiesTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImagePropertiesTest.java
index c170f69412..c238f914d9 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImagePropertiesTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImagePropertiesTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import androidx.test.runner.AndroidJUnit4;
import org.junit.Assert;
@@ -132,7 +134,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(null, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
@@ -167,7 +169,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
@@ -193,7 +195,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(null, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertFalse(properties.isValid());
+ assertThat(properties.isValid()).isFalse();
Assert.assertEquals(xmlString, properties.toString());
Assert.assertEquals(null, properties.serialize());
}
@@ -220,7 +222,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(null, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertFalse(properties.isValid());
+ assertThat(properties.isValid()).isFalse();
Assert.assertEquals(xmlString, properties.toString());
Assert.assertEquals(null, properties.serialize());
}
@@ -246,7 +248,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(null, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
@@ -269,7 +271,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
@@ -292,7 +294,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
@@ -315,7 +317,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
@@ -343,7 +345,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertFalse(properties.isValid());
+ assertThat(properties.isValid()).isFalse();
Assert.assertEquals(xmlString, properties.toString());
Assert.assertEquals(null, properties.serialize());
}
@@ -362,7 +364,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertFalse(properties.isValid());
+ assertThat(properties.isValid()).isFalse();
Assert.assertEquals(null, properties.serialize());
}
@@ -448,7 +450,7 @@ public class BipImagePropertiesTest {
Assert.assertEquals(IMAGE_HANDLE, properties.getImageHandle());
Assert.assertEquals(VERSION, properties.getVersion());
Assert.assertEquals(FRIENDLY_NAME, properties.getFriendlyName());
- Assert.assertTrue(properties.isValid());
+ assertThat(properties.isValid()).isTrue();
Assert.assertEquals(xmlString, properties.toString());
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageTest.java
index 5f028d1ba3..87ffdc5387 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipImageTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -55,7 +57,7 @@ public class BipImageTest {
Bitmap bitmap = BitmapFactory.decodeStream(expectedInputStream);
Assert.assertEquals(sImageHandle, image.getImageHandle());
- Assert.assertTrue(bitmap.sameAs(image.getImage()));
+ assertThat(bitmap.sameAs(image.getImage())).isTrue();
}
@Test
@@ -69,7 +71,7 @@ public class BipImageTest {
Bitmap bitmap = BitmapFactory.decodeStream(expectedInputStream);
Assert.assertEquals(sImageHandle, image.getImageHandle());
- Assert.assertTrue(bitmap.sameAs(image.getImage()));
+ assertThat(bitmap.sameAs(image.getImage())).isTrue();
}
@Test
@@ -79,7 +81,7 @@ public class BipImageTest {
Bitmap bitmap = BitmapFactory.decodeStream(imageInputStream);
BipImage image = new BipImage(sImageHandle, bitmap);
Assert.assertEquals(sImageHandle, image.getImageHandle());
- Assert.assertTrue(bitmap.sameAs(image.getImage()));
+ assertThat(bitmap.sameAs(image.getImage())).isTrue();
}
@Test
@@ -89,6 +91,6 @@ public class BipImageTest {
Bitmap bitmap = BitmapFactory.decodeStream(imageInputStream);
BipImage image = new BipImage(sImageHandle, bitmap);
Assert.assertEquals(sImageHandle, image.getImageHandle());
- Assert.assertTrue(bitmap.sameAs(image.getImage()));
+ assertThat(bitmap.sameAs(image.getImage())).isTrue();
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformationTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformationTest.java
index f77b87c38c..3b5893c1f1 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformationTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/bip/BipTransformationTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.avrcpcontroller;
+import static com.google.common.truth.Truth.assertThat;
+
import androidx.test.runner.AndroidJUnit4;
import org.junit.Assert;
@@ -29,7 +31,7 @@ public class BipTransformationTest {
@Test
public void testCreateEmpty() {
BipTransformation trans = new BipTransformation();
- Assert.assertFalse(trans.supportsAny());
+ assertThat(trans.supportsAny()).isFalse();
Assert.assertEquals(null, trans.toString());
}
@@ -37,15 +39,15 @@ public class BipTransformationTest {
public void testAddTransformation() {
BipTransformation trans = new BipTransformation();
trans.addTransformation(BipTransformation.CROP);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("crop", trans.toString());
trans.addTransformation(BipTransformation.STRETCH);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("stretch crop", trans.toString());
}
@@ -53,15 +55,15 @@ public class BipTransformationTest {
public void testAddExistingTransformation() {
BipTransformation trans = new BipTransformation();
trans.addTransformation(BipTransformation.CROP);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("crop", trans.toString());
trans.addTransformation(BipTransformation.CROP);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("crop", trans.toString());
}
@@ -82,16 +84,16 @@ public class BipTransformationTest {
public void testRemoveOnlyTransformation() {
BipTransformation trans = new BipTransformation();
trans.addTransformation(BipTransformation.CROP);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("crop", trans.toString());
trans.removeTransformation(BipTransformation.CROP);
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.supportsAny());
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.supportsAny()).isFalse();
Assert.assertEquals(null, trans.toString());
}
@@ -100,15 +102,15 @@ public class BipTransformationTest {
BipTransformation trans = new BipTransformation();
trans.addTransformation(BipTransformation.CROP);
trans.addTransformation(BipTransformation.STRETCH);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("stretch crop", trans.toString());
trans.removeTransformation(BipTransformation.CROP);
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("stretch", trans.toString());
}
@@ -118,9 +120,9 @@ public class BipTransformationTest {
trans.addTransformation(BipTransformation.CROP);
trans.addTransformation(BipTransformation.STRETCH);
trans.removeTransformation(BipTransformation.UNKNOWN);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("stretch crop", trans.toString());
}
@@ -130,135 +132,135 @@ public class BipTransformationTest {
trans.addTransformation(BipTransformation.CROP);
trans.addTransformation(BipTransformation.STRETCH);
trans.removeTransformation(BipTransformation.FILL);
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("stretch crop", trans.toString());
}
@Test
public void testParse_Stretch() {
BipTransformation trans = new BipTransformation("stretch");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("stretch", trans.toString());
}
@Test
public void testParse_Crop() {
BipTransformation trans = new BipTransformation("crop");
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("crop", trans.toString());
}
@Test
public void testParse_Fill() {
BipTransformation trans = new BipTransformation("Fill");
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("fill", trans.toString());
}
@Test
public void testParse_StretchFill() {
BipTransformation trans = new BipTransformation("stretch fill");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("stretch fill", trans.toString());
}
@Test
public void testParse_StretchCrop() {
BipTransformation trans = new BipTransformation("stretch crop");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
Assert.assertEquals("stretch crop", trans.toString());
}
@Test
public void testParse_FillCrop() {
BipTransformation trans = new BipTransformation("fill crop");
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
Assert.assertEquals("fill crop", trans.toString());
}
@Test
public void testParse_StretchFillCrop() {
BipTransformation trans = new BipTransformation("stretch fill crop");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("stretch fill crop", trans.toString());
}
@Test
public void testParse_CropFill() {
BipTransformation trans = new BipTransformation("crop fill");
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
Assert.assertEquals("fill crop", trans.toString());
}
@Test
public void testParse_CropFillStretch() {
BipTransformation trans = new BipTransformation("crop fill stretch");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("stretch fill crop", trans.toString());
}
@Test
public void testParse_CropFillStretchWithDuplicates() {
BipTransformation trans = new BipTransformation("stretch crop fill fill crop stretch");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("stretch fill crop", trans.toString());
}
@Test
public void testCreate_stretch() {
BipTransformation trans = new BipTransformation(BipTransformation.STRETCH);
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("stretch", trans.toString());
}
@Test
public void testCreate_fill() {
BipTransformation trans = new BipTransformation(BipTransformation.FILL);
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("fill", trans.toString());
}
@Test
public void testCreate_crop() {
BipTransformation trans = new BipTransformation(BipTransformation.CROP);
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("crop", trans.toString());
}
@Test
public void testCreate_cropArray() {
BipTransformation trans = new BipTransformation(new int[] {BipTransformation.CROP});
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("crop", trans.toString());
}
@@ -267,9 +269,9 @@ public class BipTransformationTest {
BipTransformation trans =
new BipTransformation(
new int[] {BipTransformation.STRETCH, BipTransformation.FILL});
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("stretch fill", trans.toString());
}
@@ -282,9 +284,9 @@ public class BipTransformationTest {
BipTransformation.FILL,
BipTransformation.CROP
});
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("stretch fill crop", trans.toString());
}
@@ -297,9 +299,9 @@ public class BipTransformationTest {
BipTransformation.FILL,
BipTransformation.STRETCH
});
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("stretch fill crop", trans.toString());
}
@@ -316,36 +318,36 @@ public class BipTransformationTest {
@Test
public void testParse_badTransformationOnly() {
BipTransformation trans = new BipTransformation("bad");
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals(null, trans.toString());
}
@Test
public void testParse_badTransformationMixedIn() {
BipTransformation trans = new BipTransformation("crop fill bad stretch");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("stretch fill crop", trans.toString());
}
@Test
public void testParse_badTransformationStart() {
BipTransformation trans = new BipTransformation("bad crop fill");
- Assert.assertFalse(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertTrue(trans.isSupported(BipTransformation.FILL));
- Assert.assertTrue(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isTrue();
Assert.assertEquals("fill crop", trans.toString());
}
@Test
public void testParse_badTransformationEnd() {
BipTransformation trans = new BipTransformation("stretch bad");
- Assert.assertTrue(trans.isSupported(BipTransformation.STRETCH));
- Assert.assertFalse(trans.isSupported(BipTransformation.FILL));
- Assert.assertFalse(trans.isSupported(BipTransformation.CROP));
+ assertThat(trans.isSupported(BipTransformation.STRETCH)).isTrue();
+ assertThat(trans.isSupported(BipTransformation.FILL)).isFalse();
+ assertThat(trans.isSupported(BipTransformation.CROP)).isFalse();
Assert.assertEquals("stretch", trans.toString());
}
}
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 9b242f896d..3561f4e0e7 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
@@ -140,7 +140,7 @@ public class BassClientServiceTest {
// German language code in ISO 639-3
private static final String TEST_LANGUAGE = "deu";
private static final int TEST_SOURCE_ID = 10;
- private static final int TEST_NUM_SOURCES = 2;
+ private static final int TEST_NUM_SOURCES = 1;
private final HashMap<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>();
private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mIntentQueue;
@@ -559,6 +559,9 @@ public class BassClientServiceTest {
injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID + 1);
}
}
+
+ doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice);
+ doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice1);
}
private void startSearchingForSources() {
@@ -1576,6 +1579,9 @@ public class BassClientServiceTest {
.getCallbacks()
.notifySourceAdded(
sm.getDevice(), recvState, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
+ mBassClientService
+ .getCallbacks()
+ .notifyReceiveStateChanged(sm.getDevice(), recvState.getSourceId(), recvState);
TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper());
return recvState;
@@ -1945,7 +1951,6 @@ public class BassClientServiceTest {
: BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED,
null,
(long) 0x00000001);
- verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true));
}
// Remove broadcast source
@@ -1971,6 +1976,8 @@ public class BassClientServiceTest {
for (BassClientStateMachine sm : mStateMachines.values()) {
injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID);
}
+
+ verify(mLeAudioService).activeBroadcastAssistantNotification(eq(false));
}
private void verifyRemoveMessageAndInjectSourceRemoval() {
@@ -2176,6 +2183,29 @@ public class BassClientServiceTest {
}
}
+ @Test
+ public void testSecondAddSourceWithCapacityGreaterThanOne() {
+ prepareConnectedDeviceGroup();
+
+ // Set maximum source capacity to 2
+ for (BassClientStateMachine sm : mStateMachines.values()) {
+ doReturn(2).when(sm).getMaximumSourceCapacity();
+ }
+
+ startSearchingForSources();
+ onScanResult(mSourceDevice, TEST_BROADCAST_ID);
+ onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE);
+ BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID);
+ verifyAddSourceForGroup(meta);
+ prepareRemoteSourceState(meta, true, true);
+
+ // Add another new broadcast source
+ onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1);
+ onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1);
+ BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1);
+ verifyAddSourceForGroup(newMeta);
+ }
+
/**
* Test that after multiple calls to service.addSource() with a group operation flag set, there
* are two call to service.removeSource() needed to clear the flag
@@ -6250,7 +6280,9 @@ public class BassClientServiceTest {
checkAndDispatchTimeout(
TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT);
- verifyStopBigMonitoringWithUnsync();
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerUnregisterSync(any(), any());
verifyRemoveMessageAndInjectSourceRemoval();
checkNoResumeSynchronizationByBig();
}
@@ -6280,7 +6312,9 @@ public class BassClientServiceTest {
checkAndDispatchTimeout(
TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT);
- verifyStopBigMonitoringWithoutUnsync();
+ mInOrderMethodProxy
+ .verify(mMethodProxy, never())
+ .periodicAdvertisingManagerUnregisterSync(any(), any());
verifyRemoveMessageAndInjectSourceRemoval();
checkNoResumeSynchronizationByBig();
}
@@ -6294,7 +6328,9 @@ public class BassClientServiceTest {
sinkUnintentionalWithoutScanning();
checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT);
- verifyStopBigMonitoringWithUnsync();
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerUnregisterSync(any(), any());
verifyRemoveMessageAndInjectSourceRemoval();
checkNoResumeSynchronizationByBig();
}
@@ -6308,7 +6344,9 @@ public class BassClientServiceTest {
sinkUnintentionalDuringScanning();
checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT);
- verifyStopBigMonitoringWithoutUnsync();
+ mInOrderMethodProxy
+ .verify(mMethodProxy, never())
+ .periodicAdvertisingManagerUnregisterSync(any(), any());
verifyRemoveMessageAndInjectSourceRemoval();
checkNoResumeSynchronizationByBig();
}
@@ -6681,7 +6719,9 @@ public class BassClientServiceTest {
checkAndDispatchTimeout(
TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT);
- verifyStopBigMonitoringWithUnsync();
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerUnregisterSync(any(), any());
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java
index b9baeb3ef4..919326767f 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java
@@ -49,8 +49,6 @@ import static com.android.bluetooth.bass_client.BassConstants.CLIENT_CHARACTERIS
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -61,8 +59,10 @@ import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -92,6 +92,7 @@ import android.content.Intent;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -118,6 +119,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.hamcrest.MockitoHamcrest;
@@ -278,7 +280,7 @@ public class BassClientStateMachineTest {
Assert.assertThat(
mBassClientStateMachine.getCurrentState(),
IsInstanceOf.instanceOf(BassClientStateMachine.Disconnected.class));
- assertNull(mBassClientStateMachine.mBluetoothGatt);
+ assertThat(mBassClientStateMachine.mBluetoothGatt).isNull();
}
@Test
@@ -304,7 +306,7 @@ public class BassClientStateMachineTest {
mBassClientStateMachine.getCurrentState(),
IsInstanceOf.instanceOf(BassClientStateMachine.Connecting.class));
- assertNotNull(mBassClientStateMachine.mGattCallback);
+ assertThat(mBassClientStateMachine.mGattCallback).isNotNull();
mBassClientStateMachine.notifyConnectionStateChanged(
GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
@@ -552,9 +554,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void parseScanRecord_withoutBaseData_callCancelActiveSync() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
byte[] scanRecord =
new byte[] {
0x02,
@@ -601,9 +602,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void parseScanRecord_withBaseData_callsUpdateBase() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
byte[] scanRecordWithBaseData =
new byte[] {
(byte) 0x02,
@@ -759,7 +759,8 @@ public class BassClientStateMachineTest {
/** This also tests BassClientStateMachine#processBroadcastReceiverState. */
@Test
- public void gattCallbackOnCharacteristicRead() {
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RECEIVE_STATE_PROCESSING_REFACTOR)
+ public void gattCallbackOnCharacteristicReadObsolete() {
mBassClientStateMachine.mShouldHandleMessage = false;
mBassClientStateMachine.connectGatt(true);
BluetoothGattCallback cb = mBassClientStateMachine.mGattCallback;
@@ -942,7 +943,8 @@ public class BassClientStateMachineTest {
}
@Test
- public void gattCallbackOnCharacteristicChanged() {
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RECEIVE_STATE_PROCESSING_REFACTOR)
+ public void gattCallbackOnCharacteristicChangedObsolete() {
mBassClientStateMachine.connectGatt(true);
BluetoothGattCallback cb = mBassClientStateMachine.mGattCallback;
mBassClientStateMachine.mNumOfBroadcastReceiverStates = 1;
@@ -974,6 +976,435 @@ public class BassClientStateMachineTest {
}
@Test
+ @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RECEIVE_STATE_PROCESSING_REFACTOR)
+ public void gattCallbackOnCharacteristicRead() {
+ mBassClientStateMachine.mShouldHandleMessage = false;
+ mBassClientStateMachine.connectGatt(true);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ BluetoothGattCallback cb = mBassClientStateMachine.mGattCallback;
+ BluetoothGattDescriptor desc = Mockito.mock(BluetoothGattDescriptor.class);
+ BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
+ BluetoothGattCharacteristic characteristic =
+ Mockito.mock(BluetoothGattCharacteristic.class);
+ BassClientStateMachine.BluetoothGattTestableWrapper btGatt =
+ Mockito.mock(BassClientStateMachine.BluetoothGattTestableWrapper.class);
+ when(characteristic.getUuid()).thenReturn(BassConstants.BASS_BCAST_RECEIVER_STATE);
+ when(mBassClientService.getCallbacks()).thenReturn(callbacks);
+ mBassClientStateMachine.mNumOfBroadcastReceiverStates = 2;
+
+ // Characteristic read success with null value
+ when(characteristic.getValue()).thenReturn(null);
+ cb.onCharacteristicRead(null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ InOrder inOrderCharacteristic = inOrder(characteristic);
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic).getValue();
+ InOrder inOrderCallbacks = inOrder(callbacks);
+ inOrderCallbacks
+ .verify(callbacks, never())
+ .notifyReceiveStateChanged(any(), anyInt(), any());
+ verify(characteristic, never()).getDescriptor(any());
+
+ // Characteristic read failed and mBluetoothGatt is null.
+ mBassClientStateMachine.mBluetoothGatt = null;
+ cb.onCharacteristicRead(null, characteristic, GATT_FAILURE);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic, never()).getUuid();
+ inOrderCharacteristic.verify(characteristic, never()).getValue();
+ inOrderCallbacks
+ .verify(callbacks, never())
+ .notifyReceiveStateChanged(any(), anyInt(), any());
+ assertThat(mBassClientStateMachine.mMsgWhats).contains(GATT_TXN_PROCESSED);
+ assertThat(mBassClientStateMachine.mMsgAgr1).isEqualTo(GATT_FAILURE);
+ mBassClientStateMachine.mMsgWhats.clear();
+
+ // Characteristic read failed and mBluetoothGatt is not null.
+ mBassClientStateMachine.mBluetoothGatt = btGatt;
+ when(characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG)).thenReturn(desc);
+ cb.onCharacteristicRead(null, characteristic, GATT_FAILURE);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic, never()).getUuid();
+ inOrderCharacteristic.verify(characteristic, never()).getValue();
+ inOrderCallbacks
+ .verify(callbacks, never())
+ .notifyReceiveStateChanged(any(), anyInt(), any());
+ verify(btGatt).setCharacteristicNotification(any(), anyBoolean());
+ verify(btGatt).writeDescriptor(desc);
+ verify(desc).setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
+
+ // Tests for processBroadcastReceiverState
+
+ // Empty value without any previous read/change
+ when(characteristic.getValue()).thenReturn(new byte[] {});
+ cb.onCharacteristicRead(null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(4)).getValue();
+ inOrderCallbacks
+ .verify(callbacks, never())
+ .notifyReceiveStateChanged(any(), anyInt(), any());
+
+ // Read first time first characteristic
+ int sourceId = 1;
+ int instanceId = 1234;
+ byte[] value =
+ new byte[] {
+ (byte) sourceId, // sourceId
+ (byte) (mSourceTestDevice.getAddressType() & 0xFF), // sourceAddressType
+ Utils.getByteAddress(mSourceTestDevice)[5],
+ Utils.getByteAddress(mSourceTestDevice)[4],
+ Utils.getByteAddress(mSourceTestDevice)[3],
+ Utils.getByteAddress(mSourceTestDevice)[2],
+ Utils.getByteAddress(mSourceTestDevice)[1],
+ Utils.getByteAddress(mSourceTestDevice)[0], // sourceAddress
+ 0x00, // sourceAdvSid
+ 0x00,
+ 0x00,
+ 0x00, // broadcastIdBytes
+ (byte) BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE,
+ (byte) BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE,
+ // 16 bytes badBroadcastCode
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x01, // numSubGroups
+ // SubGroup #1
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00, // audioSyncIndex
+ 0x02, // metaDataLength
+ 0x00,
+ 0x00, // metadata
+ };
+ when(characteristic.getValue()).thenReturn(value);
+ when(characteristic.getInstanceId()).thenReturn(instanceId);
+ cb.onCharacteristicRead(null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(4)).getValue();
+ ArgumentCaptor<BluetoothLeBroadcastReceiveState> receiveStateCaptor =
+ ArgumentCaptor.forClass(BluetoothLeBroadcastReceiveState.class);
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceAdded(any(), any(), eq(BluetoothStatusCodes.REASON_REMOTE_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Read first time second (last) characteristic
+ int sourceId2 = 2;
+ int instanceId2 = 4321;
+ value[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX] = (byte) sourceId2;
+ when(characteristic.getInstanceId()).thenReturn(instanceId2);
+ cb.onCharacteristicRead(null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(4)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceAdded(any(), any(), eq(BluetoothStatusCodes.REASON_REMOTE_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId2), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+ }
+
+ /** This also tests BassClientStateMachine#processBroadcastReceiverState. */
+ @Test
+ @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RECEIVE_STATE_PROCESSING_REFACTOR)
+ public void gattCallbackOnCharacteristicChanged() {
+ mBassClientStateMachine.connectGatt(true);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ BluetoothGattCallback cb = mBassClientStateMachine.mGattCallback;
+ mBassClientStateMachine.mNumOfBroadcastReceiverStates = 1;
+ BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
+ when(mBassClientService.getCallbacks()).thenReturn(callbacks);
+
+ BluetoothGattCharacteristic characteristic =
+ Mockito.mock(BluetoothGattCharacteristic.class);
+ when(characteristic.getUuid()).thenReturn(BassConstants.BASS_BCAST_RECEIVER_STATE);
+
+ // Null value
+ when(characteristic.getValue()).thenReturn(null);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ InOrder inOrderCharacteristic = inOrder(characteristic);
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic).getValue();
+ InOrder inOrderCallbacks = inOrder(callbacks);
+ inOrderCallbacks
+ .verify(callbacks, never())
+ .notifyReceiveStateChanged(any(), anyInt(), any());
+
+ // Empty value without any previous read/change
+ when(characteristic.getValue()).thenReturn(new byte[] {});
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks, never())
+ .notifyReceiveStateChanged(any(), anyInt(), any());
+
+ // Sync value, first time
+ int sourceId = 1;
+ byte[] value =
+ new byte[] {
+ (byte) sourceId, // sourceId
+ (byte) (mSourceTestDevice.getAddressType() & 0xFF), // sourceAddressType
+ Utils.getByteAddress(mSourceTestDevice)[5],
+ Utils.getByteAddress(mSourceTestDevice)[4],
+ Utils.getByteAddress(mSourceTestDevice)[3],
+ Utils.getByteAddress(mSourceTestDevice)[2],
+ Utils.getByteAddress(mSourceTestDevice)[1],
+ Utils.getByteAddress(mSourceTestDevice)[0], // sourceAddress
+ 0x00, // sourceAdvSid
+ 0x00,
+ 0x00,
+ 0x00, // broadcastIdBytes
+ (byte) BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE,
+ (byte) BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE,
+ // 16 bytes badBroadcastCode
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x01, // numSubGroups
+ // SubGroup #1
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00, // audioSyncIndex
+ 0x02, // metaDataLength
+ 0x00,
+ 0x00, // metadata
+ };
+ when(characteristic.getValue()).thenReturn(value);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ ArgumentCaptor<BluetoothLeBroadcastReceiveState> receiveStateCaptor =
+ ArgumentCaptor.forClass(BluetoothLeBroadcastReceiveState.class);
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceAdded(any(), any(), eq(BluetoothStatusCodes.REASON_REMOTE_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Empty value to indicates removing source from device by remote
+ when(characteristic.getValue()).thenReturn(new byte[] {});
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceRemoved(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_REMOTE_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mEmptyTestDevice);
+
+ // Sync value again
+ mBassClientStateMachine.mPendingOperation = ADD_BCAST_SOURCE;
+ when(characteristic.getValue()).thenReturn(value);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceAdded(any(), any(), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Empty value to indicates removing source from device by local app
+ mBassClientStateMachine.mPendingOperation = REMOVE_BCAST_SOURCE;
+ when(characteristic.getValue()).thenReturn(new byte[] {});
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceRemoved(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mEmptyTestDevice);
+
+ // Sync value again
+ mBassClientStateMachine.mPendingOperation = ADD_BCAST_SOURCE;
+ when(characteristic.getValue()).thenReturn(value);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceAdded(any(), any(), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Empty value to indicates removing source from device by stack (source switch)
+ BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
+ mBassClientStateMachine.mPendingSourceToSwitch = metadata;
+ when(characteristic.getValue()).thenReturn(new byte[] {});
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceRemoved(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mEmptyTestDevice);
+ assertThat(mBassClientStateMachine.mMsgWhats).contains(ADD_BCAST_SOURCE);
+ assertThat(mBassClientStateMachine.mMsgObj).isEqualTo(metadata);
+
+ // Sync value again
+ mBassClientStateMachine.mPendingOperation = ADD_BCAST_SOURCE;
+ when(characteristic.getValue()).thenReturn(value);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCharacteristic.verify(characteristic).getUuid();
+ inOrderCharacteristic.verify(characteristic, times(2)).getValue();
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceAdded(any(), any(), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Update value - PA SyncInfo Request
+ value[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX] =
+ BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCINFO_REQUEST;
+ PeriodicAdvertisementResult paResult = Mockito.mock(PeriodicAdvertisementResult.class);
+ when(mBassClientService.getPeriodicAdvertisementResult(any(), anyInt()))
+ .thenReturn(paResult);
+ int syncHandle = 100;
+ when(paResult.getSyncHandle()).thenReturn(syncHandle);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceModified(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ int serviceData = 0x000000FF & sourceId;
+ serviceData = serviceData << 8;
+ // advA matches EXT_ADV_ADDRESS
+ // also matches source address (as we would have written)
+ serviceData = serviceData & (~BassConstants.ADV_ADDRESS_DONT_MATCHES_EXT_ADV_ADDRESS);
+ serviceData = serviceData & (~BassConstants.ADV_ADDRESS_DONT_MATCHES_SOURCE_ADV_ADDRESS);
+ verify(mMethodProxy)
+ .periodicAdvertisingManagerTransferSync(
+ any(), any(), eq(serviceData), eq(syncHandle));
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Update value - PA SyncInfo Request, local broadcast
+ mBassClientStateMachine.mPendingMetadata = createBroadcastMetadata();
+ when(mBassClientService.isLocalBroadcast(any(BluetoothLeBroadcastMetadata.class)))
+ .thenReturn(true);
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceModified(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ serviceData = 0x000000FF & sourceId;
+ serviceData = serviceData << 8;
+ // Address we set in the Source Address can differ from the address in the air
+ serviceData = serviceData | BassConstants.ADV_ADDRESS_DONT_MATCHES_SOURCE_ADV_ADDRESS;
+ verify(mMethodProxy)
+ .periodicAdvertisingManagerTransferSetInfo(
+ any(), any(), eq(serviceData), anyInt(), any());
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Update value - Broadcast Code
+ value[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX] =
+ BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED;
+ value[BassConstants.BCAST_RCVR_STATE_ENC_STATUS_IDX] =
+ BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_CODE_REQUIRED;
+ mBassClientStateMachine.mSetBroadcastCodePending = true;
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceModified(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ assertThat(mBassClientStateMachine.mMsgWhats).contains(SET_BCAST_CODE);
+ assertThat(mBassClientStateMachine.mMsgAgr1)
+ .isEqualTo(BassClientStateMachine.ARGTYPE_RCVSTATE);
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+
+ // Update value - Pending Remove
+ value[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX] =
+ BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE;
+ mBassClientStateMachine.mIsPendingRemove = true;
+ cb.onCharacteristicChanged(null, characteristic);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifySourceModified(
+ any(), eq(sourceId), eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
+ assertThat(mBassClientStateMachine.mMsgWhats).contains(REMOVE_BCAST_SOURCE);
+ assertThat(mBassClientStateMachine.mMsgAgr1).isEqualTo(sourceId);
+ inOrderCallbacks
+ .verify(callbacks)
+ .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture());
+ Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice);
+ }
+
+ @Test
public void gattCharacteristicWrite() {
mBassClientStateMachine.connectGatt(true);
BluetoothGattCallback cb = mBassClientStateMachine.mGattCallback;
@@ -1131,7 +1562,7 @@ public class BassClientStateMachineTest {
mBassClientStateMachine.mBluetoothGatt = btGatt;
sendMessageAndVerifyTransition(msg, BassClientStateMachine.Disconnected.class);
verify(btGatt).close();
- assertNull(mBassClientStateMachine.mBluetoothGatt);
+ assertThat(mBassClientStateMachine.mBluetoothGatt).isNull();
}
@Test
@@ -1160,7 +1591,7 @@ public class BassClientStateMachineTest {
Message msg = mBassClientStateMachine.obtainMessage(CONNECT_TIMEOUT, mTestDevice);
sendMessageAndVerifyTransition(msg, BassClientStateMachine.Disconnected.class);
verify(btGatt).close();
- assertNull(mBassClientStateMachine.mBluetoothGatt);
+ assertThat(mBassClientStateMachine.mBluetoothGatt).isNull();
}
@Test
@@ -1223,7 +1654,7 @@ public class BassClientStateMachineTest {
noneConnectedMsg.obj = BluetoothProfile.STATE_DISCONNECTING;
sendMessageAndVerifyTransition(noneConnectedMsg, BassClientStateMachine.Disconnected.class);
verify(btGatt).close();
- assertNull(mBassClientStateMachine.mBluetoothGatt);
+ assertThat(mBassClientStateMachine.mBluetoothGatt).isNull();
}
@Test
@@ -1290,9 +1721,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void sendPsyncActiveMessage_inConnectedState() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
initToConnectedState();
// need this to ensure expected mock behavior for getActiveSyncedSource
when(mBassClientService.getActiveSyncedSources(any())).thenReturn(null);
@@ -1313,9 +1743,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void sendSelectBcastSourceMessage_inConnectedState() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
initToConnectedState();
byte[] scanRecord =
@@ -1394,10 +1823,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void sendAddBcastSourceMessage_inConnectedState() {
- mSetFlagsRule.enableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
-
initToConnectedState();
BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
@@ -1430,9 +1857,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void sendReachedMaxSourceLimitMessage_inConnectedState() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
initToConnectedState();
// need this to ensure expected mock behavior for getActiveSyncedSource
when(mBassClientService.getActiveSyncedSources(any())).thenReturn(null);
@@ -1794,7 +2220,7 @@ public class BassClientStateMachineTest {
sendMessageAndVerifyTransition(
msgToNoneConnectedState, BassClientStateMachine.Disconnected.class);
verify(btGatt).close();
- assertNull(mBassClientStateMachine.mBluetoothGatt);
+ assertThat(mBassClientStateMachine.mBluetoothGatt).isNull();
}
/** This also tests BassClientStateMachine#sendPendingCallbacks */
@@ -2030,9 +2456,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void selectBcastSource_withSameBroadcastId() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
final int testSyncHandle = 1;
initToConnectedState();
@@ -2128,9 +2553,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void addBcastSource_withCachedScanResults() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
initToConnectedState();
BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
@@ -2239,9 +2663,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void periodicAdvertisingCallbackOnSyncLost_notifySourceLost() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
PeriodicAdvertisingCallback cb = mBassClientStateMachine.mLocalPeriodicAdvCallback;
BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
int syncHandle = 1;
@@ -2254,9 +2677,8 @@ public class BassClientStateMachineTest {
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void periodicAdvertisingCallbackOnBigInfoAdvertisingReport_updateRssi() {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE);
PeriodicAdvertisingCallback cb = mBassClientStateMachine.mLocalPeriodicAdvCallback;
BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
int testRssi = -40;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
index b5ab6027aa..1d7e3a2c2d 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
@@ -456,6 +456,43 @@ public class ActiveDeviceManagerTest {
}
@Test
+ public void switchActiveDeviceFromLeToHfp_noFallbackToLe() {
+ // Turn off the dual mode audio flag
+ Utils.setDualModeAudioStateForTesting(false);
+
+ // Connect A2DP + HFP device, set it not active
+ a2dpConnected(mA2dpHeadsetDevice, true);
+ headsetConnected(mA2dpHeadsetDevice, true);
+ a2dpActiveDeviceChanged(null);
+ headsetActiveDeviceChanged(null);
+ mTestLooper.dispatchAll();
+
+ Mockito.clearInvocations(mHeadsetService);
+ Mockito.clearInvocations(mA2dpService);
+ Mockito.clearInvocations(mLeAudioService);
+
+ // Connect LE Audio device, set it to inactive
+ leAudioConnected(mLeAudioDevice);
+ leAudioActiveDeviceChanged(mLeAudioDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
+ assertThat(mActiveDeviceManager.getLeAudioActiveDevice()).isEqualTo(mLeAudioDevice);
+
+ Mockito.clearInvocations(mHeadsetService);
+ Mockito.clearInvocations(mA2dpService);
+ Mockito.clearInvocations(mLeAudioService);
+
+ // Set LE Audio device to inactive
+ // Set A2DP + HFP device to active
+ leAudioActiveDeviceChanged(null);
+ headsetActiveDeviceChanged(mA2dpHeadsetDevice);
+ mTestLooper.dispatchAll();
+ // A2DP + HFP should now be active
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ verify(mA2dpService).setActiveDevice(mA2dpHeadsetDevice);
+ }
+
+ @Test
public void hfpActivatedAfterTimeout_shouldActivateA2dpAgain() {
a2dpConnected(mA2dpHeadsetDevice, true);
headsetConnected(mA2dpHeadsetDevice, true);
@@ -771,7 +808,7 @@ public class ActiveDeviceManagerTest {
// Don't call mA2dpService.setActiveDevice()
verify(mA2dpService, never()).setActiveDevice(mA2dpDevice);
Assert.assertEquals(mA2dpDevice, mActiveDeviceManager.getA2dpActiveDevice());
- Assert.assertTrue(mActiveDeviceManager.getHearingAidActiveDevices().isEmpty());
+ assertThat(mActiveDeviceManager.getHearingAidActiveDevices()).isEmpty();
}
/** A Hearing Aid is connected. Then a Headset active device is explicitly set. */
@@ -790,7 +827,7 @@ public class ActiveDeviceManagerTest {
// Don't call mHeadsetService.setActiveDevice()
verify(mHeadsetService, never()).setActiveDevice(mHeadsetDevice);
Assert.assertEquals(mHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
- Assert.assertTrue(mActiveDeviceManager.getHearingAidActiveDevices().isEmpty());
+ assertThat(mActiveDeviceManager.getHearingAidActiveDevices()).isEmpty();
}
@Test
@@ -817,6 +854,66 @@ public class ActiveDeviceManagerTest {
verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
}
+ /**
+ * LE Audio is connected but is not ready for stream (no available context types). Check if it's
+ * not used as fallback device from A2DP
+ */
+ @Test
+ public void leAudioFallbackA2dpToLeaudio_notReadyForStream() {
+ when(mLeAudioService.isGroupAvailableForStream(anyInt())).thenReturn(false);
+ leAudioConnected(mLeAudioDevice);
+ a2dpConnected(mA2dpDevice, true);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ verify(mA2dpService).setActiveDevice(mA2dpDevice);
+
+ a2dpDisconnected(mA2dpDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ }
+
+ /**
+ * LE Audio is connected but is not ready for stream (no available context types). Check if it's
+ * not used as fallback device from A2DP
+ */
+ @Test
+ public void leAudioFallbackLeaudioToLeaudio_notReadyForStream() {
+ /* LeAudio device from group 1 - not ready for stream */
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+ /* LeAudio device from group 1 - ready for stream */
+ when(mLeAudioService.getGroupId(mSecondaryAudioDevice)).thenReturn(2);
+ when(mLeAudioService.isGroupAvailableForStream(1)).thenReturn(false);
+ when(mLeAudioService.isGroupAvailableForStream(2)).thenReturn(true);
+ leAudioConnected(mLeAudioDevice);
+ leAudioConnected(mSecondaryAudioDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ verify(mLeAudioService).setActiveDevice(mSecondaryAudioDevice);
+
+ leAudioDisconnected(mSecondaryAudioDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ }
+
+ /**
+ * LE Audio is connected but is not ready for stream (no available context types). Check if it's
+ * not used as fallback device from ASHA
+ */
+ @Test
+ public void leAudioFallbackAshaToLeaudio_notReadyForStream() {
+ when(mLeAudioService.isGroupAvailableForStream(anyInt())).thenReturn(false);
+
+ leAudioConnected(mLeAudioDevice);
+ hearingAidConnected(mHearingAidDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ verify(mHearingAidService).setActiveDevice(mHearingAidDevice);
+
+ hearingAidDisconnected(mHearingAidDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
+ }
+
/** Two LE Audio are connected. Should set the second one active. */
@Test
public void secondLeAudioConnected_setSecondLeAudioActive() {
@@ -1107,7 +1204,7 @@ public class ActiveDeviceManagerTest {
verify(mLeAudioService).removeActiveDevice(true);
verify(mA2dpService).setActiveDevice(mA2dpDevice);
Assert.assertEquals(mA2dpDevice, mActiveDeviceManager.getA2dpActiveDevice());
- Assert.assertNull(mActiveDeviceManager.getLeAudioActiveDevice());
+ assertThat(mActiveDeviceManager.getLeAudioActiveDevice()).isNull();
}
/** An LE Audio is connected. Then a Headset active device is explicitly set. */
@@ -1125,7 +1222,7 @@ public class ActiveDeviceManagerTest {
verify(mLeAudioService).removeActiveDevice(true);
verify(mHeadsetService).setActiveDevice(mHeadsetDevice);
Assert.assertEquals(mHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
- Assert.assertNull(mActiveDeviceManager.getLeAudioActiveDevice());
+ assertThat(mActiveDeviceManager.getLeAudioActiveDevice()).isNull();
}
/**
@@ -1518,9 +1615,9 @@ public class ActiveDeviceManagerTest {
mTestLooper.dispatchAll();
// Verify setting LEA active fails when all supported classic audio profiles are not active
verify(mLeAudioService).setActiveDevice(mDualModeAudioDevice);
- Assert.assertNull(mActiveDeviceManager.getLeAudioActiveDevice());
- Assert.assertNull(mActiveDeviceManager.getA2dpActiveDevice());
- Assert.assertNull(mActiveDeviceManager.getHfpActiveDevice());
+ assertThat(mActiveDeviceManager.getLeAudioActiveDevice()).isNull();
+ assertThat(mActiveDeviceManager.getA2dpActiveDevice()).isNull();
+ assertThat(mActiveDeviceManager.getHfpActiveDevice()).isNull();
when(mLeAudioService.setActiveDevice(any())).thenReturn(true);
when(mLeAudioService.removeActiveDevice(anyBoolean())).thenReturn(true);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
index a1463b49f5..bac576e7e7 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
@@ -155,6 +155,7 @@ public class AdapterServiceTest {
private @Mock AdapterNativeInterface mNativeInterface;
private @Mock BluetoothKeystoreNativeInterface mKeystoreNativeInterface;
private @Mock BluetoothQualityReportNativeInterface mQualityNativeInterface;
+ private @Mock BluetoothHciVendorSpecificNativeInterface mHciVendorSpecificNativeInterface;
private @Mock SdpManagerNativeInterface mSdpNativeInterface;
private @Mock AdvertiseManagerNativeInterface mAdvertiseNativeInterface;
private @Mock DistanceMeasurementNativeInterface mDistanceNativeInterface;
@@ -226,6 +227,7 @@ public class AdapterServiceTest {
AdapterNativeInterface.setInstance(mNativeInterface);
BluetoothKeystoreNativeInterface.setInstance(mKeystoreNativeInterface);
BluetoothQualityReportNativeInterface.setInstance(mQualityNativeInterface);
+ BluetoothHciVendorSpecificNativeInterface.setInstance(mHciVendorSpecificNativeInterface);
SdpManagerNativeInterface.setInstance(mSdpNativeInterface);
AdvertiseManagerNativeInterface.setInstance(mAdvertiseNativeInterface);
DistanceMeasurementNativeInterface.setInstance(mDistanceNativeInterface);
@@ -354,6 +356,7 @@ public class AdapterServiceTest {
AdapterNativeInterface.setInstance(null);
BluetoothKeystoreNativeInterface.setInstance(null);
BluetoothQualityReportNativeInterface.setInstance(null);
+ BluetoothHciVendorSpecificNativeInterface.setInstance(null);
SdpManagerNativeInterface.setInstance(null);
AdvertiseManagerNativeInterface.setInstance(null);
DistanceMeasurementNativeInterface.setInstance(null);
@@ -979,6 +982,37 @@ public class AdapterServiceTest {
}
@Test
+ @EnableFlags(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API)
+ public void testIdentityAddressType() {
+ RemoteDevices remoteDevices = mAdapterService.getRemoteDevices();
+ remoteDevices.addDeviceProperties(Utils.getBytesFromAddress((TEST_BT_ADDR_1)));
+
+ int identityAddressTypePublic = 0x00; // Should map to BluetoothDevice.ADDRESS_TYPE_PUBLIC
+ int identityAddressTypeRandom = 0x01; // Should map to BluetoothDevice.ADDRESS_TYPE_RANDOM
+
+ remoteDevices.leAddressAssociateCallback(
+ Utils.getBytesFromAddress(TEST_BT_ADDR_1),
+ Utils.getBytesFromAddress(TEST_BT_ADDR_2),
+ identityAddressTypePublic);
+
+ BluetoothDevice.BluetoothAddress bluetoothAddress =
+ mAdapterService.getIdentityAddressWithType(TEST_BT_ADDR_1);
+ assertThat(bluetoothAddress.getAddress()).isEqualTo(TEST_BT_ADDR_2);
+ assertThat(bluetoothAddress.getAddressType())
+ .isEqualTo(BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+
+ remoteDevices.leAddressAssociateCallback(
+ Utils.getBytesFromAddress(TEST_BT_ADDR_1),
+ Utils.getBytesFromAddress(TEST_BT_ADDR_2),
+ identityAddressTypeRandom);
+
+ bluetoothAddress = mAdapterService.getIdentityAddressWithType(TEST_BT_ADDR_1);
+ assertThat(bluetoothAddress.getAddress()).isEqualTo(TEST_BT_ADDR_2);
+ assertThat(bluetoothAddress.getAddressType())
+ .isEqualTo(BluetoothDevice.ADDRESS_TYPE_RANDOM);
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_IDENTITY_ADDRESS_NULL_IF_NOT_KNOWN)
public void testIdentityAddressNullIfUnknown() {
BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterSuspendTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterSuspendTest.java
index 65bf7560de..f234b25e0f 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterSuspendTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterSuspendTest.java
@@ -25,7 +25,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.hardware.display.DisplayManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.os.test.TestLooper;
import androidx.test.InstrumentationRegistry;
@@ -44,7 +44,7 @@ import org.mockito.junit.MockitoRule;
@RunWith(AndroidJUnit4.class)
public class AdapterSuspendTest {
private TestLooper mTestLooper;
- private DisplayManager mDisplayManager;
+ private DeviceStateManager mDeviceStateManager;
private AdapterSuspend mAdapterSuspend;
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@@ -54,15 +54,15 @@ public class AdapterSuspendTest {
public void setUp() throws Exception {
Context context = InstrumentationRegistry.getTargetContext();
mTestLooper = new TestLooper();
- mDisplayManager = context.getSystemService(DisplayManager.class);
+ mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
mAdapterSuspend =
new AdapterSuspend(
- mAdapterNativeInterface, mTestLooper.getLooper(), mDisplayManager);
+ mAdapterNativeInterface, mTestLooper.getLooper(), mDeviceStateManager);
}
private void triggerSuspend() throws Exception {
- mAdapterSuspend.handleSuspend();
+ mAdapterSuspend.handleSuspend(true);
}
private void triggerResume() throws Exception {
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 e1dc5a07ce..f24c1ff2aa 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
@@ -17,6 +17,8 @@ package com.android.bluetooth.btservice;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -212,14 +214,14 @@ public class BondStateMachineTest {
RemoteDevices.DeviceProperties pendingDeviceProperties =
mRemoteDevices.addDeviceProperties(TEST_BT_ADDR_BYTES_2);
BluetoothDevice pendingDevice = pendingDeviceProperties.getDevice();
- Assert.assertNotNull(pendingDevice);
+ assertThat(pendingDevice).isNotNull();
mBondStateMachine.sendIntent(pendingDevice, BOND_BONDED, TEST_BOND_REASON, false);
RemoteDevices.DeviceProperties testDeviceProperties =
mRemoteDevices.addDeviceProperties(TEST_BT_ADDR_BYTES);
testDeviceProperties.mUuids = TEST_UUIDS;
BluetoothDevice testDevice = testDeviceProperties.getDevice();
- Assert.assertNotNull(testDevice);
+ assertThat(testDevice).isNotNull();
Message bondingMsg = mBondStateMachine.obtainMessage(BondStateMachine.BONDING_STATE_CHANGE);
bondingMsg.obj = testDevice;
@@ -240,7 +242,7 @@ public class BondStateMachineTest {
mBondStateMachine.sendMessage(bondedMsg);
TestUtils.waitForLooperToFinishScheduledTask(mBondStateMachine.getHandler().getLooper());
- Assert.assertTrue(mBondStateMachine.mPendingBondedDevices.isEmpty());
+ assertThat(mBondStateMachine.mPendingBondedDevices).isEmpty();
}
private void resetRemoteDevice(int deviceType) {
@@ -248,7 +250,7 @@ public class BondStateMachineTest {
mRemoteDevices.reset();
mDeviceProperties = mRemoteDevices.addDeviceProperties(TEST_BT_ADDR_BYTES);
mDevice = mDeviceProperties.getDevice();
- Assert.assertNotNull(mDevice);
+ assertThat(mDevice).isNotNull();
mDeviceProperties.mDeviceType = deviceType;
mBondStateMachine.mPendingBondedDevices.clear();
}
@@ -606,10 +608,12 @@ public class BondStateMachineTest {
}
if (shouldDelayMessageExist) {
- Assert.assertTrue(mBondStateMachine.hasMessage(mBondStateMachine.BONDED_INTENT_DELAY));
+ assertThat(mBondStateMachine.hasMessage(mBondStateMachine.BONDED_INTENT_DELAY))
+ .isTrue();
mBondStateMachine.removeMessage(mBondStateMachine.BONDED_INTENT_DELAY);
} else {
- Assert.assertFalse(mBondStateMachine.hasMessage(mBondStateMachine.BONDED_INTENT_DELAY));
+ assertThat(mBondStateMachine.hasMessage(mBondStateMachine.BONDED_INTENT_DELAY))
+ .isFalse();
}
}
@@ -734,7 +738,7 @@ public class BondStateMachineTest {
}
private void verifyBondStateChangeIntent(int oldState, int newState, Intent intent) {
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
Assert.assertEquals(BluetoothDevice.ACTION_BOND_STATE_CHANGED, intent.getAction());
Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(newState, intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1));
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java
index 7cd13fe4b4..fab8ab02dc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/CompanionManagerTest.java
@@ -15,6 +15,8 @@
*/
package com.android.bluetooth.btservice;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothDevice;
@@ -30,7 +32,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -103,13 +104,13 @@ public class CompanionManagerTest {
@Test
public void testIsCompanionDevice() {
loadCompanionInfoHelper(TEST_DEVICE, CompanionManager.COMPANION_TYPE_NONE);
- Assert.assertTrue(mCompanionManager.isCompanionDevice(TEST_DEVICE));
+ assertThat(mCompanionManager.isCompanionDevice(TEST_DEVICE)).isTrue();
loadCompanionInfoHelper(TEST_DEVICE, CompanionManager.COMPANION_TYPE_PRIMARY);
- Assert.assertTrue(mCompanionManager.isCompanionDevice(TEST_DEVICE));
+ assertThat(mCompanionManager.isCompanionDevice(TEST_DEVICE)).isTrue();
loadCompanionInfoHelper(TEST_DEVICE, CompanionManager.COMPANION_TYPE_SECONDARY);
- Assert.assertTrue(mCompanionManager.isCompanionDevice(TEST_DEVICE));
+ assertThat(mCompanionManager.isCompanionDevice(TEST_DEVICE)).isTrue();
}
@Test
@@ -158,12 +159,12 @@ public class CompanionManagerTest {
mCompanionManager.getGattConnParameters(
TEST_DEVICE, CompanionManager.GATT_CONN_LATENCY, priority);
- Assert.assertTrue(max >= min);
- Assert.assertTrue(max >= minInterval);
- Assert.assertTrue(min >= minInterval);
- Assert.assertTrue(max <= maxInterval);
- Assert.assertTrue(min <= maxInterval);
- Assert.assertTrue(latency >= minLatency);
- Assert.assertTrue(latency <= maxLatency);
+ assertThat(max).isAtLeast(min);
+ assertThat(max).isAtLeast(minInterval);
+ assertThat(min).isAtLeast(minInterval);
+ assertThat(max).isAtMost(maxInterval);
+ assertThat(min).isAtMost(maxInterval);
+ assertThat(latency).isAtLeast(minLatency);
+ assertThat(latency).isAtMost(maxLatency);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java
index dba15c5d1a..aa49e0d0a7 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java
@@ -15,6 +15,7 @@
*/
package com.android.bluetooth.btservice;
+import static com.google.common.truth.Truth.assertThat;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -154,10 +155,10 @@ public class MetricsLoggerTest {
Assert.assertEquals(2, metricsProto.getProfileConnectionStatsCount());
Map<ProfileId, ProfileConnectionStats> profileConnectionCountMap =
getProfileUsageStatsMap(metricsProto.getProfileConnectionStatsList());
- Assert.assertTrue(profileConnectionCountMap.containsKey(ProfileId.AVRCP));
+ assertThat(profileConnectionCountMap).containsKey(ProfileId.AVRCP);
Assert.assertEquals(
2, profileConnectionCountMap.get(ProfileId.AVRCP).getNumTimesConnected());
- Assert.assertTrue(profileConnectionCountMap.containsKey(ProfileId.HEADSET));
+ assertThat(profileConnectionCountMap).containsKey(ProfileId.HEADSET);
Assert.assertEquals(
1, profileConnectionCountMap.get(ProfileId.HEADSET).getNumTimesConnected());
// Verify that MetricsLogger's internal state is cleared after a dump
@@ -197,15 +198,15 @@ public class MetricsLoggerTest {
@Test
public void testAddAndSendCountersCornerCases() {
- Assert.assertTrue(mTestableMetricsLogger.isInitialized());
+ assertThat(mTestableMetricsLogger.isInitialized()).isTrue();
mTestableMetricsLogger.cacheCount(1, -1);
mTestableMetricsLogger.cacheCount(3, 0);
mTestableMetricsLogger.cacheCount(2, 10);
mTestableMetricsLogger.cacheCount(2, Long.MAX_VALUE - 8L);
mTestableMetricsLogger.drainBufferedCounters();
- Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1));
- Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(3));
+ assertThat(mTestableMetricsLogger.mTestableCounters).doesNotContainKey(1);
+ assertThat(mTestableMetricsLogger.mTestableCounters).doesNotContainKey(3);
Assert.assertEquals(
Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue());
}
@@ -225,20 +226,20 @@ public class MetricsLoggerTest {
@Test
public void testMetricsLoggerNotInit() {
mTestableMetricsLogger.close();
- Assert.assertFalse(mTestableMetricsLogger.cacheCount(1, 1));
+ assertThat(mTestableMetricsLogger.cacheCount(1, 1)).isFalse();
mTestableMetricsLogger.drainBufferedCounters();
- Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1));
+ assertThat(mTestableMetricsLogger.mTestableCounters).doesNotContainKey(1);
}
@Test
public void testAddAndSendCountersDoubleInit() {
- Assert.assertTrue(mTestableMetricsLogger.isInitialized());
+ assertThat(mTestableMetricsLogger.isInitialized()).isTrue();
// sending a null adapterService will crash in case the double init no longer works
mTestableMetricsLogger.init(null, mRemoteDevices);
}
@Test
- public void testDeviceNameToSha() {
+ public void testDeviceNameToSha() throws IOException {
initTestingBloomfilter();
for (Map.Entry<String, String> entry : SANITIZED_DEVICE_NAME_MAP.entrySet()) {
String deviceName = entry.getKey();
@@ -265,7 +266,7 @@ public class MetricsLoggerTest {
Assert.assertEquals(bluetoothRemoteDeviceInformation.getOui(), oui);
} catch (InvalidProtocolBufferException e) {
- Assert.assertNull(e.getMessage()); // test failure here
+ assertThat(e.getMessage()).isNull(); // test failure here
}
}
@@ -292,21 +293,17 @@ public class MetricsLoggerTest {
}
@Test
- public void uploadEmptyDeviceName() {
+ public void uploadEmptyDeviceName() throws IOException {
initTestingBloomfilter();
Assert.assertEquals("", mTestableMetricsLogger.logAllowlistedDeviceNameHash(1, ""));
}
- private void initTestingBloomfilter() {
+ private void initTestingBloomfilter() throws IOException {
byte[] bloomfilterData =
DeviceBloomfilterGenerator.hexStringToByteArray(
DeviceBloomfilterGenerator.BLOOM_FILTER_DEFAULT);
- try {
- mTestableMetricsLogger.setBloomfilter(
- BloomFilter.readFrom(
- new ByteArrayInputStream(bloomfilterData), Funnels.byteArrayFunnel()));
- } catch (IOException e) {
- Assert.assertTrue(false);
- }
+ mTestableMetricsLogger.setBloomfilter(
+ BloomFilter.readFrom(
+ new ByteArrayInputStream(bloomfilterData), Funnels.byteArrayFunnel()));
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java
index 7372288fac..2e7225e74b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ProfileServiceTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.btservice;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -32,12 +34,10 @@ import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
-import com.android.bluetooth.a2dp.A2dpNativeInterface;
import com.android.bluetooth.a2dpsink.A2dpSinkNativeInterface;
import com.android.bluetooth.avrcp.AvrcpNativeInterface;
import com.android.bluetooth.avrcpcontroller.AvrcpControllerNativeInterface;
import com.android.bluetooth.btservice.storage.DatabaseManager;
-import com.android.bluetooth.csip.CsipSetCoordinatorNativeInterface;
import com.android.bluetooth.hearingaid.HearingAidNativeInterface;
import com.android.bluetooth.hfp.HeadsetNativeInterface;
import com.android.bluetooth.hfpclient.NativeInterface;
@@ -81,7 +81,6 @@ public class ProfileServiceTest {
private int[] mProfiles;
- @Mock private A2dpNativeInterface mA2dpNativeInterface;
@Mock private A2dpSinkNativeInterface mA2dpSinkNativeInterface;
@Mock private AvrcpNativeInterface mAvrcpNativeInterface;
@Mock private AvrcpControllerNativeInterface mAvrcpControllerNativeInterface;
@@ -91,7 +90,6 @@ public class ProfileServiceTest {
@Mock private HidDeviceNativeInterface mHidDeviceNativeInterface;
@Mock private HidHostNativeInterface mHidHostNativeInterface;
@Mock private PanNativeInterface mPanNativeInterface;
- @Mock private CsipSetCoordinatorNativeInterface mCsipSetCoordinatorInterface;
@Mock private LeAudioNativeInterface mLeAudioInterface;
private void setProfileState(int profile, int state) {
@@ -134,7 +132,6 @@ public class ProfileServiceTest {
if (Looper.myLooper() == null) {
Looper.prepare();
}
- Assert.assertNotNull(Looper.myLooper());
doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
doNothing().when(mAdapterService).addProfile(any());
@@ -156,13 +153,14 @@ public class ProfileServiceTest {
profile ->
profile != BluetoothProfile.HAP_CLIENT
&& profile != BluetoothProfile.VOLUME_CONTROL
- && profile != BluetoothProfile.GATT)
+ && profile != BluetoothProfile.CSIP_SET_COORDINATOR
+ && profile != BluetoothProfile.GATT
+ && profile != BluetoothProfile.A2DP)
.toArray();
TestUtils.setAdapterService(mAdapterService);
- Assert.assertNotNull(AdapterService.getAdapterService());
+ assertThat(AdapterService.getAdapterService()).isNotNull();
- A2dpNativeInterface.setInstance(mA2dpNativeInterface);
A2dpSinkNativeInterface.setInstance(mA2dpSinkNativeInterface);
AvrcpNativeInterface.setInstance(mAvrcpNativeInterface);
AvrcpControllerNativeInterface.setInstance(mAvrcpControllerNativeInterface);
@@ -172,7 +170,6 @@ public class ProfileServiceTest {
HidDeviceNativeInterface.setInstance(mHidDeviceNativeInterface);
HidHostNativeInterface.setInstance(mHidHostNativeInterface);
PanNativeInterface.setInstance(mPanNativeInterface);
- CsipSetCoordinatorNativeInterface.setInstance(mCsipSetCoordinatorInterface);
LeAudioNativeInterface.setInstance(mLeAudioInterface);
}
@@ -182,7 +179,6 @@ public class ProfileServiceTest {
TestUtils.clearAdapterService(mAdapterService);
mAdapterService = null;
mProfiles = null;
- A2dpNativeInterface.setInstance(null);
A2dpSinkNativeInterface.setInstance(null);
AvrcpNativeInterface.setInstance(null);
AvrcpControllerNativeInterface.setInstance(null);
@@ -192,7 +188,6 @@ public class ProfileServiceTest {
HidDeviceNativeInterface.setInstance(null);
HidHostNativeInterface.setInstance(null);
PanNativeInterface.setInstance(null);
- CsipSetCoordinatorNativeInterface.setInstance(null);
LeAudioNativeInterface.setInstance(null);
}
@@ -243,9 +238,9 @@ public class ProfileServiceTest {
List<ProfileService> stoppedArguments = stops.getAllValues();
Assert.assertEquals(startedArguments.size(), stoppedArguments.size());
for (ProfileService service : startedArguments) {
- Assert.assertTrue(stoppedArguments.contains(service));
+ assertThat(stoppedArguments).contains(service);
stoppedArguments.remove(service);
- Assert.assertFalse(stoppedArguments.contains(service));
+ assertThat(stoppedArguments).doesNotContain(service);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
index 845a53b77c..28747da680 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
@@ -2,6 +2,8 @@ package com.android.bluetooth.btservice;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -99,7 +101,7 @@ public class RemoteDevicesTest {
// Verify that a handler message is sent by the method call
mRemoteDevices.updateUuids(mDevice1);
Message msg = mTestLooperManager.next();
- Assert.assertNotNull(msg);
+ assertThat(msg).isNotNull();
// Verify that executing that message results in a direct call and broadcast intent
mTestLooperManager.execute(msg);
@@ -113,7 +115,7 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -124,7 +126,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -153,14 +155,14 @@ public class RemoteDevicesTest {
int batteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating with invalid battery level does not trigger the intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
verify(mAdapterService, never()).sendBroadcast(any(), anyString(), any());
// Verify that device property stays null after invalid update
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
verifyNoMoreInteractions(mAdapterService);
}
@@ -170,14 +172,14 @@ public class RemoteDevicesTest {
int batteryLevel = 101;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating invalid battery level does not trigger the intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
verify(mAdapterService, never()).sendBroadcast(any(), anyString(), any());
// Verify that device property stays null after invalid update
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
verifyNoMoreInteractions(mAdapterService);
}
@@ -185,11 +187,11 @@ public class RemoteDevicesTest {
@Test
public void testResetBatteryLevel_testResetBeforeUpdate() {
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that resetting battery level keeps device property null
mRemoteDevices.resetBatteryLevel(mDevice1, /* fromBas= */ false);
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
verifyNoMoreInteractions(mAdapterService);
}
@@ -199,7 +201,7 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -210,7 +212,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -225,7 +227,7 @@ public class RemoteDevicesTest {
mDevice1, BluetoothDevice.BATTERY_LEVEL_UNKNOWN, mIntentArgument);
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify value is reset in properties
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(),
BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
@@ -250,7 +252,7 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -261,7 +263,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -279,7 +281,7 @@ public class RemoteDevicesTest {
mDevice1, BluetoothDevice.BATTERY_LEVEL_UNKNOWN, mIntentArgument);
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify value is reset in properties
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(),
BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
@@ -300,10 +302,10 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
BatteryService oldBatteryService = setBatteryServiceForTesting(mDevice1);
- Assert.assertTrue(mRemoteDevices.hasBatteryService(mDevice1));
+ assertThat(mRemoteDevices.hasBatteryService(mDevice1)).isTrue();
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -314,7 +316,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -324,7 +326,7 @@ public class RemoteDevicesTest {
BluetoothProfile.STATE_DISCONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel());
@@ -340,7 +342,7 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -351,7 +353,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel());
@@ -381,7 +383,7 @@ public class RemoteDevicesTest {
BluetoothDevice.ACTION_ACL_DISCONNECTED, mIntentArgument.getValue().getAction());
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify value is reset in properties
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel());
@@ -400,7 +402,7 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that ACTION_HF_INDICATORS_VALUE_CHANGED intent updates battery level
mRemoteDevices.onHfIndicatorValueChanged(
@@ -417,19 +419,19 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that ACTION_HF_INDICATORS_VALUE_CHANGED intent updates battery level
mRemoteDevices.onHfIndicatorValueChanged(mDevice1, batteryLevel, 3);
verify(mAdapterService, never()).sendBroadcast(any(), anyString());
// Verify that device property is still null after invalid update
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
}
@Test
public void testOnVendorSpecificHeadsetEvent_testCorrectPlantronicsXEvent() {
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that correct ACTION_VENDOR_SPECIFIC_HEADSET_EVENT updates battery level
mRemoteDevices.onVendorSpecificHeadsetEvent(
@@ -448,7 +450,7 @@ public class RemoteDevicesTest {
@Test
public void testOnVendorSpecificHeadsetEvent_testCorrectAppleBatteryVsc() {
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that correct ACTION_VENDOR_SPECIFIC_HEADSET_EVENT updates battery level
mRemoteDevices.onVendorSpecificHeadsetEvent(
@@ -577,7 +579,7 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -588,7 +590,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -608,7 +610,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify value is reset in properties
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(),
BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
@@ -629,10 +631,10 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
BatteryService oldBatteryService = setBatteryServiceForTesting(mDevice1);
- Assert.assertTrue(mRemoteDevices.hasBatteryService(mDevice1));
+ assertThat(mRemoteDevices.hasBatteryService(mDevice1)).isTrue();
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -643,7 +645,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -653,7 +655,7 @@ public class RemoteDevicesTest {
BluetoothProfile.STATE_DISCONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel());
@@ -668,10 +670,10 @@ public class RemoteDevicesTest {
int batteryLevel2 = 20;
BatteryService oldBatteryService = setBatteryServiceForTesting(mDevice1);
- Assert.assertTrue(mRemoteDevices.hasBatteryService(mDevice1));
+ assertThat(mRemoteDevices.hasBatteryService(mDevice1)).isTrue();
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -682,7 +684,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -712,10 +714,10 @@ public class RemoteDevicesTest {
int batteryLevel = 10;
BatteryService oldBatteryService = setBatteryServiceForTesting(mDevice1);
- Assert.assertTrue(mRemoteDevices.hasBatteryService(mDevice1));
+ assertThat(mRemoteDevices.hasBatteryService(mDevice1)).isTrue();
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /* fromBas= */ false);
@@ -726,7 +728,7 @@ public class RemoteDevicesTest {
Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());
// Verify that user can get battery level after the update
- Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNotNull();
Assert.assertEquals(
mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(), batteryLevel);
@@ -750,7 +752,7 @@ public class RemoteDevicesTest {
int batteryLevel = 3;
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
// Verify that ACTION_AG_EVENT intent updates battery level
mRemoteDevices.onAgBatteryLevelChanged(mDevice1, batteryLevel);
@@ -768,7 +770,7 @@ public class RemoteDevicesTest {
@EnableFlags(Flags.FLAG_FIX_ADD_DEVICE_PROPERTIES)
public void testMultipleAddDeviceProperties() {
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
DeviceProperties prop1 =
mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1));
DeviceProperties prop2 =
@@ -779,7 +781,7 @@ public class RemoteDevicesTest {
@Test
public void testSetgetHfAudioPolicyForRemoteAg() {
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1));
@@ -793,7 +795,7 @@ public class RemoteDevicesTest {
.build();
deviceProp.setHfAudioPolicyForRemoteAg(policies);
- // Verify that the audio policy properties are set and get propperly
+ // Verify that the audio policy properties are set and get properly
Assert.assertEquals(
policies,
mRemoteDevices.getDeviceProperties(mDevice1).getHfAudioPolicyForRemoteAg());
@@ -806,13 +808,13 @@ public class RemoteDevicesTest {
.getSupportedProfilesBitMask();
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1));
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(mDevice1);
deviceProp.setIsCoordinatedSetMember(true);
- Assert.assertTrue(deviceProp.isCoordinatedSetMember());
+ assertThat(deviceProp.isCoordinatedSetMember()).isTrue();
}
@Test
@@ -822,18 +824,18 @@ public class RemoteDevicesTest {
.getSupportedProfilesBitMask();
// Verify that device property is null initially
- Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));
+ assertThat(mRemoteDevices.getDeviceProperties(mDevice1)).isNull();
mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1));
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(mDevice1);
deviceProp.setIsCoordinatedSetMember(true);
- Assert.assertFalse(deviceProp.isCoordinatedSetMember());
+ assertThat(deviceProp.isCoordinatedSetMember()).isFalse();
}
@Test
public void testIsDeviceNull() {
- Assert.assertNull(mRemoteDevices.getDeviceProperties(null));
+ assertThat(mRemoteDevices.getDeviceProperties(null)).isNull();
}
private static void verifyBatteryLevelChangedIntent(
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/SilenceDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/SilenceDeviceManagerTest.java
index a880b5ce13..c616c90aa7 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/SilenceDeviceManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/SilenceDeviceManagerTest.java
@@ -18,6 +18,8 @@ package com.android.bluetooth.btservice;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -109,7 +111,7 @@ public class SilenceDeviceManagerTest {
// Set pre-state for mSilenceDeviceManager
if (wasSilenced) {
- Assert.assertTrue(mSilenceDeviceManager.setSilenceMode(mTestDevice, true));
+ assertThat(mSilenceDeviceManager.setSilenceMode(mTestDevice, true)).isTrue();
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
verify(mAdapterService, times(++mVerifyCount))
.sendBroadcastAsUser(
@@ -118,7 +120,7 @@ public class SilenceDeviceManagerTest {
}
// Set silence state and check whether state changed successfully
- Assert.assertTrue(mSilenceDeviceManager.setSilenceMode(mTestDevice, enableSilence));
+ assertThat(mSilenceDeviceManager.setSilenceMode(mTestDevice, enableSilence)).isTrue();
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
Assert.assertEquals(enableSilence, mSilenceDeviceManager.getSilenceMode(mTestDevice));
@@ -135,7 +137,7 @@ public class SilenceDeviceManagerTest {
a2dpDisconnected(mTestDevice);
headsetDisconnected(mTestDevice);
- Assert.assertFalse(mSilenceDeviceManager.getSilenceMode(mTestDevice));
+ assertThat(mSilenceDeviceManager.getSilenceMode(mTestDevice)).isFalse();
if (enableSilence) {
// If the silence mode is enabled, it should be automatically disabled
// after device is disconnected.
@@ -149,9 +151,9 @@ public class SilenceDeviceManagerTest {
void testSetGetDeviceSilenceDisconnectedCase(boolean enableSilence) {
ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
// Set silence mode and it should stay disabled
- Assert.assertTrue(mSilenceDeviceManager.setSilenceMode(mTestDevice, enableSilence));
+ assertThat(mSilenceDeviceManager.setSilenceMode(mTestDevice, enableSilence)).isTrue();
TestUtils.waitForLooperToFinishScheduledTask(mLooper);
- Assert.assertFalse(mSilenceDeviceManager.getSilenceMode(mTestDevice));
+ assertThat(mSilenceDeviceManager.getSilenceMode(mTestDevice)).isFalse();
// Should be no intent been broadcasted
verify(mAdapterService, times(mVerifyCount))
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java
index 276db29dda..668743ad31 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreServiceTest.java
@@ -16,12 +16,13 @@
package com.android.bluetooth.btservice.bluetoothkeystore;
+import static com.google.common.truth.Truth.assertThat;
+
import android.os.Binder;
import android.os.Process;
import android.util.Log;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
@@ -98,7 +99,6 @@ public final class BluetoothKeystoreServiceTest {
public void setUp() {
Assume.assumeTrue("Ignore test when the user is not primary.", isPrimaryUser());
mBluetoothKeystoreService = new BluetoothKeystoreService(mMockNativeInterface, true);
- Assert.assertNotNull(mBluetoothKeystoreService);
// backup origin config data.
try {
mConfigData = Files.readAllLines(Paths.get(CONFIG_FILE_PATH));
@@ -203,10 +203,13 @@ public final class BluetoothKeystoreServiceTest {
// over write config
overwriteConfigFile(mConfigTestData);
// load config file.
- Assert.assertTrue(parseConfigFile(CONFIG_FILE_PATH));
+ assertThat(parseConfigFile(CONFIG_FILE_PATH)).isTrue();
// make sure it is same with createNameDecryptKeyResult
- Assert.assertTrue(
- doCompareMap(mNameDecryptKeyResult, mBluetoothKeystoreService.getNameDecryptKey()));
+ assertThat(
+ doCompareMap(
+ mNameDecryptKeyResult,
+ mBluetoothKeystoreService.getNameDecryptKey()))
+ .isTrue();
}
@Test
@@ -216,9 +219,11 @@ public final class BluetoothKeystoreServiceTest {
// Wait for encryption to complete
mBluetoothKeystoreService.stopThread();
- Assert.assertTrue(
- doCompareKeySet(
- mNameDecryptKeyResult, mBluetoothKeystoreService.getNameEncryptKey()));
+ assertThat(
+ doCompareKeySet(
+ mNameDecryptKeyResult,
+ mBluetoothKeystoreService.getNameEncryptKey()))
+ .isTrue();
}
@Test
@@ -229,24 +234,27 @@ public final class BluetoothKeystoreServiceTest {
// clear up memory.
mBluetoothKeystoreService.cleanupMemory();
// load encryption file and do encryption.
- Assert.assertTrue(loadEncryptionFile(CONFIG_FILE_ENCRYPTION_PATH, true));
+ assertThat(loadEncryptionFile(CONFIG_FILE_ENCRYPTION_PATH, true)).isTrue();
// Wait for encryption to complete
mBluetoothKeystoreService.stopThread();
- Assert.assertTrue(
- doCompareMap(mNameDecryptKeyResult, mBluetoothKeystoreService.getNameDecryptKey()));
+ assertThat(
+ doCompareMap(
+ mNameDecryptKeyResult,
+ mBluetoothKeystoreService.getNameDecryptKey()))
+ .isTrue();
}
@Test
public void testCompareHashFile() {
// save config checksum.
- Assert.assertTrue(setEncryptKeyOrRemoveKey(CONFIG_FILE_PREFIX, CONFIG_FILE_HASH));
+ assertThat(setEncryptKeyOrRemoveKey(CONFIG_FILE_PREFIX, CONFIG_FILE_HASH)).isTrue();
// clean up memory
mBluetoothKeystoreService.cleanupMemory();
- Assert.assertTrue(loadEncryptionFile(CONFIG_CHECKSUM_ENCRYPTION_PATH, false));
+ assertThat(loadEncryptionFile(CONFIG_CHECKSUM_ENCRYPTION_PATH, false)).isTrue();
- Assert.assertTrue(compareFileHash(CONFIG_FILE_PATH));
+ assertThat(compareFileHash(CONFIG_FILE_PATH)).isTrue();
}
@Test
@@ -255,25 +263,27 @@ public final class BluetoothKeystoreServiceTest {
// need to creat encrypted file.
testParserFile();
// created encrypted file
- Assert.assertTrue(setEncryptKeyOrRemoveKey(CONFIG_FILE_PREFIX, CONFIG_FILE_HASH));
+ assertThat(setEncryptKeyOrRemoveKey(CONFIG_FILE_PREFIX, CONFIG_FILE_HASH)).isTrue();
// clean up memory and stop thread.
mBluetoothKeystoreService.cleanupForCommonCriteriaModeEnable();
// new mBluetoothKeystoreService and the Common Criteria mode is false.
mBluetoothKeystoreService = new BluetoothKeystoreService(mMockNativeInterface, false);
- Assert.assertNotNull(mBluetoothKeystoreService);
mBluetoothKeystoreService.loadConfigData();
// check encryption file clean up.
- Assert.assertFalse(Files.exists(Paths.get(CONFIG_CHECKSUM_ENCRYPTION_PATH)));
- Assert.assertFalse(Files.exists(Paths.get(CONFIG_FILE_ENCRYPTION_PATH)));
+ assertThat(Files.exists(Paths.get(CONFIG_CHECKSUM_ENCRYPTION_PATH))).isFalse();
+ assertThat(Files.exists(Paths.get(CONFIG_FILE_ENCRYPTION_PATH))).isFalse();
// remove hash data avoid interfering result.
mBluetoothKeystoreService.getNameDecryptKey().remove(CONFIG_FILE_PREFIX);
- Assert.assertTrue(
- doCompareMap(mNameDecryptKeyResult, mBluetoothKeystoreService.getNameDecryptKey()));
+ assertThat(
+ doCompareMap(
+ mNameDecryptKeyResult,
+ mBluetoothKeystoreService.getNameDecryptKey()))
+ .isTrue();
}
@Test
@@ -285,6 +295,6 @@ public final class BluetoothKeystoreServiceTest {
mBluetoothKeystoreService = new BluetoothKeystoreService(mMockNativeInterface, true);
mBluetoothKeystoreService.loadConfigData();
- Assert.assertTrue(mBluetoothKeystoreService.getCompareResult() == 0);
+ assertThat(mBluetoothKeystoreService.getCompareResult()).isEqualTo(0);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
index 5f1b8e0f97..bcaccfd94f 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
@@ -16,7 +16,8 @@
package com.android.bluetooth.btservice.storage;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
@@ -50,8 +51,6 @@ import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.flags.Flags;
-import com.google.common.truth.Truth;
-
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Assert;
@@ -167,7 +166,7 @@ public final class DatabaseManagerTest {
mDatabaseManager.getA2dpOptionalCodecsEnabled(mTestDevice));
for (int id = 0; id < MAX_META_ID; id++) {
- Assert.assertNull(mDatabaseManager.getCustomMeta(mTestDevice, id));
+ assertThat(mDatabaseManager.getCustomMeta(mTestDevice, id)).isNull();
}
mDatabaseManager.factoryReset();
@@ -524,16 +523,16 @@ public final class DatabaseManagerTest {
mSetFlagsRule.disableFlags(Flags.FLAG_AUTO_CONNECT_ON_MULTIPLE_HFP_WHEN_NO_A2DP_DEVICE);
// Verify pre-conditions to ensure a fresh test
Assert.assertEquals(0, mDatabaseManager.mMetadataCache.size());
- Assert.assertNotNull(mTestDevice);
- Assert.assertNotNull(mTestDevice2);
- Assert.assertNull(mDatabaseManager.getMostRecentlyActiveHfpDevice());
+ assertThat(mTestDevice).isNotNull();
+ assertThat(mTestDevice2).isNotNull();
+ assertThat(mDatabaseManager.getMostRecentlyActiveHfpDevice()).isNull();
// Set the first device's connection
mDatabaseManager.setConnection(mTestDevice, BluetoothProfile.HEADSET);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress()).isActiveHfpDevice);
+ assertThat(mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress()).isActiveHfpDevice)
+ .isTrue();
List<BluetoothDevice> mostRecentlyConnectedDevicesOrdered =
mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(mTestDevice, mDatabaseManager.getMostRecentlyActiveHfpDevice());
@@ -544,10 +543,10 @@ public final class DatabaseManagerTest {
mDatabaseManager.setConnection(mTestDevice2, BluetoothProfile.HEADSET);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress()).isActiveHfpDevice);
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress()).isActiveHfpDevice);
+ assertThat(mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress()).isActiveHfpDevice)
+ .isFalse();
+ assertThat(mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress()).isActiveHfpDevice)
+ .isTrue();
Assert.assertEquals(mTestDevice2, mDatabaseManager.getMostRecentlyActiveHfpDevice());
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(2, mostRecentlyConnectedDevicesOrdered.size());
@@ -558,9 +557,9 @@ public final class DatabaseManagerTest {
mDatabaseManager.setDisconnection(mTestDevice, BluetoothProfile.HEADSET);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress()).isActiveHfpDevice);
- Assert.assertNotNull(mDatabaseManager.getMostRecentlyActiveHfpDevice());
+ assertThat(mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress()).isActiveHfpDevice)
+ .isFalse();
+ assertThat(mDatabaseManager.getMostRecentlyActiveHfpDevice()).isNotNull();
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(2, mostRecentlyConnectedDevicesOrdered.size());
Assert.assertEquals(mTestDevice, mostRecentlyConnectedDevicesOrdered.get(1));
@@ -577,17 +576,18 @@ public final class DatabaseManagerTest {
mSetFlagsRule.disableFlags(Flags.FLAG_AUTO_CONNECT_ON_MULTIPLE_HFP_WHEN_NO_A2DP_DEVICE);
// Verify pre-conditions to ensure a fresh test
Assert.assertEquals(0, mDatabaseManager.mMetadataCache.size());
- Assert.assertNotNull(mTestDevice);
- Assert.assertNotNull(mTestDevice2);
- Assert.assertNull(mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
+ assertThat(mTestDevice).isNotNull();
+ assertThat(mTestDevice2).isNotNull();
+ assertThat(mDatabaseManager.getMostRecentlyConnectedA2dpDevice()).isNull();
// Set the first device's connection
mDatabaseManager.setConnection(mTestDevice, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isTrue();
List<BluetoothDevice> mostRecentlyConnectedDevicesOrdered =
mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(mTestDevice, mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
@@ -598,12 +598,14 @@ public final class DatabaseManagerTest {
mDatabaseManager.setConnection(mTestDevice2, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isTrue();
Assert.assertEquals(mTestDevice2, mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(2, mostRecentlyConnectedDevicesOrdered.size());
@@ -614,12 +616,14 @@ public final class DatabaseManagerTest {
mDatabaseManager.setConnection(mTestDevice, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isTrue();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
Assert.assertEquals(mTestDevice, mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(2, mostRecentlyConnectedDevicesOrdered.size());
@@ -630,13 +634,15 @@ public final class DatabaseManagerTest {
mDatabaseManager.setDisconnection(mTestDevice, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertNull(mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(mDatabaseManager.getMostRecentlyConnectedA2dpDevice()).isNull();
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(2, mostRecentlyConnectedDevicesOrdered.size());
Assert.assertEquals(mTestDevice, mostRecentlyConnectedDevicesOrdered.get(0));
@@ -646,16 +652,19 @@ public final class DatabaseManagerTest {
mDatabaseManager.setConnection(mTestDevice3, BluetoothProfile.HEADSET);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
- .is_active_a2dp_device);
- Assert.assertNull(mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(mDatabaseManager.getMostRecentlyConnectedA2dpDevice()).isNull();
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(3, mostRecentlyConnectedDevicesOrdered.size());
Assert.assertEquals(mTestDevice3, mostRecentlyConnectedDevicesOrdered.get(0));
@@ -666,15 +675,18 @@ public final class DatabaseManagerTest {
mDatabaseManager.setConnection(mTestDevice, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
- .is_active_a2dp_device);
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isTrue();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
Assert.assertEquals(mTestDevice, mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(3, mostRecentlyConnectedDevicesOrdered.size());
@@ -686,15 +698,18 @@ public final class DatabaseManagerTest {
mDatabaseManager.setConnection(mTestDevice3, BluetoothProfile.HEADSET);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
- .is_active_a2dp_device);
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isTrue();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
Assert.assertEquals(mTestDevice, mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(3, mostRecentlyConnectedDevicesOrdered.size());
@@ -706,15 +721,18 @@ public final class DatabaseManagerTest {
mDatabaseManager.setDisconnection(mTestDevice2, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertTrue(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
- .is_active_a2dp_device);
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isTrue();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
Assert.assertEquals(mTestDevice, mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(3, mostRecentlyConnectedDevicesOrdered.size());
@@ -726,16 +744,19 @@ public final class DatabaseManagerTest {
mDatabaseManager.setDisconnection(mTestDevice, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
- .is_active_a2dp_device);
- Assert.assertNull(mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(mDatabaseManager.getMostRecentlyConnectedA2dpDevice()).isNull();
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(3, mostRecentlyConnectedDevicesOrdered.size());
Assert.assertEquals(mTestDevice3, mostRecentlyConnectedDevicesOrdered.get(0));
@@ -746,16 +767,19 @@ public final class DatabaseManagerTest {
mDatabaseManager.setDisconnection(mTestDevice3, BluetoothProfile.A2DP);
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
- .is_active_a2dp_device);
- Assert.assertFalse(
- mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
- .is_active_a2dp_device);
- Assert.assertNull(mDatabaseManager.getMostRecentlyConnectedA2dpDevice());
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice2.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(
+ mDatabaseManager.mMetadataCache.get(mTestDevice3.getAddress())
+ .is_active_a2dp_device)
+ .isFalse();
+ assertThat(mDatabaseManager.getMostRecentlyConnectedA2dpDevice()).isNull();
mostRecentlyConnectedDevicesOrdered = mDatabaseManager.getMostRecentlyConnectedDevices();
Assert.assertEquals(3, mostRecentlyConnectedDevicesOrdered.size());
Assert.assertEquals(mTestDevice3, mostRecentlyConnectedDevicesOrdered.get(0));
@@ -859,7 +883,7 @@ public final class DatabaseManagerTest {
device.put("unthethered_left_charging", testString);
device.put("unthethered_right_charging", testString);
device.put("unthethered_case_charging", testString);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -986,7 +1010,7 @@ public final class DatabaseManagerTest {
device.put("untethered_left_charging", testString);
device.put("untethered_right_charging", testString);
device.put("untethered_case_charging", testString);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1132,7 +1156,7 @@ public final class DatabaseManagerTest {
device.put("untethered_left_charging", testString);
device.put("untethered_right_charging", testString);
device.put("untethered_case_charging", testString);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1201,7 +1225,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1229,7 +1253,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1256,7 +1280,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 107 to 108
@@ -1280,7 +1304,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 108 to 109
@@ -1304,7 +1328,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 109 to 110
@@ -1328,7 +1352,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 111 to 112
@@ -1352,7 +1376,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 112 to 113
@@ -1378,7 +1402,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 113 to 114
@@ -1402,7 +1426,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1432,7 +1456,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1459,7 +1483,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 116 to 117
@@ -1485,7 +1509,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 117 to 118
@@ -1509,7 +1533,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
@@ -1534,7 +1558,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 119 to 120
@@ -1558,7 +1582,7 @@ public final class DatabaseManagerTest {
ContentValues device = new ContentValues();
device.put("address", TEST_BT_ADDR);
device.put("migrated", false);
- assertThat(
+ Assert.assertThat(
db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
CoreMatchers.not(-1));
// Migrate database from 120 to 121
@@ -1577,27 +1601,27 @@ public final class DatabaseManagerTest {
/** Helper function to check whether the database has the expected column */
void assertHasColumn(Cursor cursor, String columnName, boolean hasColumn) {
if (hasColumn) {
- assertThat(cursor.getColumnIndex(columnName), CoreMatchers.not(-1));
+ Assert.assertThat(cursor.getColumnIndex(columnName), CoreMatchers.not(-1));
} else {
- assertThat(cursor.getColumnIndex(columnName), CoreMatchers.is(-1));
+ Assert.assertThat(cursor.getColumnIndex(columnName), CoreMatchers.is(-1));
}
}
/** Helper function to check whether the database has the expected value */
void assertColumnIntData(Cursor cursor, String columnName, int value) {
- assertThat(cursor.getInt(cursor.getColumnIndex(columnName)), CoreMatchers.is(value));
+ Assert.assertThat(cursor.getInt(cursor.getColumnIndex(columnName)), CoreMatchers.is(value));
}
/** Helper function to check whether the column data type is BLOB */
void assertColumnBlob(Cursor cursor, String columnName) {
- assertThat(
+ Assert.assertThat(
cursor.getType(cursor.getColumnIndex(columnName)),
CoreMatchers.is(Cursor.FIELD_TYPE_BLOB));
}
/** Helper function to check the BLOB data in a column is expected */
void assertColumnBlobData(Cursor cursor, String columnName, byte[] data) {
- assertThat(cursor.getBlob(cursor.getColumnIndex(columnName)), CoreMatchers.is(data));
+ Assert.assertThat(cursor.getBlob(cursor.getColumnIndex(columnName)), CoreMatchers.is(data));
}
void restartDatabaseManagerHelper() {
@@ -1725,7 +1749,7 @@ public final class DatabaseManagerTest {
verify(mAdapterService, times(verifyTime)).onMetadataChanged(mTestDevice, key, value);
Assert.assertEquals(value, mDatabaseManager.getCustomMeta(mTestDevice, key));
} else {
- Assert.assertNull(mDatabaseManager.getCustomMeta(mTestDevice, key));
+ assertThat(mDatabaseManager.getCustomMeta(mTestDevice, key)).isNull();
return;
}
// Wait for database update
@@ -1758,7 +1782,7 @@ public final class DatabaseManagerTest {
// Check for callback and get value
Assert.assertEquals(policy, mDatabaseManager.getAudioPolicyMetadata(mTestDevice));
} else {
- Assert.assertNull(mDatabaseManager.getAudioPolicyMetadata(mTestDevice));
+ assertThat(mDatabaseManager.getAudioPolicyMetadata(mTestDevice)).isNull();
return;
}
// Wait for database update
@@ -1796,8 +1820,8 @@ public final class DatabaseManagerTest {
mDatabaseManager.setPreferredAudioProfiles(groupDevices, preferencesToSet));
Bundle testDevicePreferences = mDatabaseManager.getPreferredAudioProfiles(mTestDevice);
Bundle testDevice2Preferences = mDatabaseManager.getPreferredAudioProfiles(mTestDevice2);
- Assert.assertNotNull(testDevicePreferences);
- Assert.assertNotNull(testDevice2Preferences);
+ assertThat(testDevicePreferences).isNotNull();
+ assertThat(testDevice2Preferences).isNotNull();
Assert.assertEquals(
expectedPreferences.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY),
@@ -1825,8 +1849,8 @@ public final class DatabaseManagerTest {
restartDatabaseManagerHelper();
testDevicePreferences = mDatabaseManager.getPreferredAudioProfiles(mTestDevice);
testDevice2Preferences = mDatabaseManager.getPreferredAudioProfiles(mTestDevice2);
- Assert.assertNotNull(testDevicePreferences);
- Assert.assertNotNull(testDevice2Preferences);
+ assertThat(testDevicePreferences).isNotNull();
+ assertThat(testDevice2Preferences).isNotNull();
Assert.assertEquals(
expectedPreferences.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY),
@@ -1868,6 +1892,6 @@ public final class DatabaseManagerTest {
mDatabaseManager.setCustomMeta(mTestDevice, key, newValue);
- Truth.assertThat(future.get()).isEqualTo(newValue);
+ assertThat(future.get()).isEqualTo(newValue);
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java
index 77bb8b522c..f9e5ab429c 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java
@@ -17,20 +17,46 @@
package com.android.bluetooth.csip;
-import static org.mockito.Mockito.*;
-
-import android.bluetooth.*;
+import static android.bluetooth.BluetoothCsipSetCoordinator.ACTION_CSIS_DEVICE_AVAILABLE;
+import static android.bluetooth.BluetoothDevice.BOND_BONDED;
+import static android.bluetooth.BluetoothDevice.BOND_BONDING;
+import static android.bluetooth.BluetoothDevice.BOND_NONE;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
+import static android.bluetooth.BluetoothProfile.EXTRA_PREVIOUS_STATE;
+import static android.bluetooth.BluetoothProfile.EXTRA_STATE;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
+
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.BluetoothUuid;
-import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.bluetooth.IBluetoothCsipSetCoordinator;
+import android.bluetooth.IBluetoothCsipSetCoordinatorLockCallback;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Looper;
import android.os.ParcelUuid;
import android.os.RemoteException;
+import android.os.test.TestLooper;
import androidx.test.filters.MediumTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
@@ -40,521 +66,289 @@ import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.le_audio.LeAudioService;
+import org.hamcrest.Matcher;
+import org.hamcrest.core.AllOf;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Spy;
+import org.mockito.hamcrest.MockitoHamcrest;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.HashMap;
import java.util.List;
import java.util.UUID;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeoutException;
@MediumTest
@RunWith(AndroidJUnit4.class)
public class CsipSetCoordinatorServiceTest {
- private final String mFlagDexmarker = System.getProperty("dexmaker.share_classloader", "false");
-
- private Context mTargetContext;
- private BluetoothAdapter mAdapter;
- private BluetoothDevice mTestDevice;
- private BluetoothDevice mTestDevice2;
- private BluetoothDevice mTestDevice3;
- private CsipSetCoordinatorService mService;
- private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mIntentQueue;
- private BroadcastReceiver mCsipSetCoordinatorIntentReceiver;
- private static final int TIMEOUT_MS = 1000;
-
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+ @Spy private ServiceFactory mServiceFactory = new ServiceFactory();
@Mock private AdapterService mAdapterService;
@Mock private LeAudioService mLeAudioService;
- @Spy private ServiceFactory mServiceFactory = new ServiceFactory();
@Mock private DatabaseManager mDatabaseManager;
- @Mock private CsipSetCoordinatorNativeInterface mCsipSetCoordinatorNativeInterface;
+ @Mock private CsipSetCoordinatorNativeInterface mNativeInterface;
@Mock private IBluetoothCsipSetCoordinatorLockCallback mCsipSetCoordinatorLockCallback;
- @Before
- public void setUp() throws Exception {
- if (!mFlagDexmarker.equals("true")) {
- System.setProperty("dexmaker.share_classloader", "true");
- }
+ // private final Context mTargetContext =
+ // InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
+ private final BluetoothDevice mDevice = TestUtils.getTestDevice(mAdapter, 0);
+ private final BluetoothDevice mDevice2 = TestUtils.getTestDevice(mAdapter, 1);
+ private final BluetoothDevice mDevice3 = TestUtils.getTestDevice(mAdapter, 2);
- mTargetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- Assert.assertNotNull(Looper.myLooper());
+ private CsipSetCoordinatorService mService;
+ private InOrder mInOrder;
+ private TestLooper mLooper;
+ private final CsipSetCoordinatorNativeInterface mNativeCallback =
+ new CsipSetCoordinatorNativeInterface();
- TestUtils.setAdapterService(mAdapterService);
+ @Before
+ public void setUp() throws Exception {
doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
-
- mAdapter = BluetoothAdapter.getDefaultAdapter();
-
- CsipSetCoordinatorNativeInterface.setInstance(mCsipSetCoordinatorNativeInterface);
- startService();
- mService.mServiceFactory = mServiceFactory;
- when(mServiceFactory.getLeAudioService()).thenReturn(mLeAudioService);
-
- // Override the timeout value to speed up the test
- CsipSetCoordinatorStateMachine.sConnectTimeoutMs = TIMEOUT_MS; // 1s
-
- IntentFilter filter = new IntentFilter();
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- filter.addAction(BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothCsipSetCoordinator.ACTION_CSIS_DEVICE_AVAILABLE);
- filter.addAction(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE);
-
- mCsipSetCoordinatorIntentReceiver = new CsipSetCoordinatorIntentReceiver();
- mTargetContext.registerReceiver(mCsipSetCoordinatorIntentReceiver, filter);
-
- mTestDevice = TestUtils.getTestDevice(mAdapter, 0);
- when(mCsipSetCoordinatorNativeInterface.getDevice(getByteAddress(mTestDevice)))
- .thenReturn(mTestDevice);
- mTestDevice2 = TestUtils.getTestDevice(mAdapter, 1);
- when(mCsipSetCoordinatorNativeInterface.getDevice(getByteAddress(mTestDevice2)))
- .thenReturn(mTestDevice2);
- mTestDevice3 = TestUtils.getTestDevice(mAdapter, 2);
- when(mCsipSetCoordinatorNativeInterface.getDevice(getByteAddress(mTestDevice3)))
- .thenReturn(mTestDevice3);
-
- doReturn(BluetoothDevice.BOND_BONDED)
- .when(mAdapterService)
- .getBondState(any(BluetoothDevice.class));
+ doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService).getBondState(any());
doReturn(new ParcelUuid[] {BluetoothUuid.COORDINATED_SET})
.when(mAdapterService)
- .getRemoteUuids(any(BluetoothDevice.class));
-
- mIntentQueue = new HashMap<>();
- mIntentQueue.put(mTestDevice, new LinkedBlockingQueue<>());
- mIntentQueue.put(mTestDevice2, new LinkedBlockingQueue<>());
- mIntentQueue.put(mTestDevice3, new LinkedBlockingQueue<>());
- }
-
- @After
- public void tearDown() throws Exception {
- if (!mFlagDexmarker.equals("true")) {
- System.setProperty("dexmaker.share_classloader", mFlagDexmarker);
- }
+ .getRemoteUuids(any());
- if (Looper.myLooper() == null) {
- return;
- }
+ doReturn(CONNECTION_POLICY_ALLOWED)
+ .when(mDatabaseManager)
+ .getProfileConnectionPolicy(any(), anyInt());
+ doReturn(true).when(mNativeInterface).connect(any());
+ doReturn(true).when(mNativeInterface).disconnect(any());
+ doReturn(new ParcelUuid[] {BluetoothUuid.COORDINATED_SET})
+ .when(mAdapterService)
+ .getRemoteUuids(any());
- if (mService == null) {
- return;
- }
+ doReturn(mLeAudioService).when(mServiceFactory).getLeAudioService();
- stopService();
- CsipSetCoordinatorNativeInterface.setInstance(null);
- mTargetContext.unregisterReceiver(mCsipSetCoordinatorIntentReceiver);
- TestUtils.clearAdapterService(mAdapterService);
- mIntentQueue.clear();
- }
+ mInOrder = inOrder(mAdapterService);
+ mLooper = new TestLooper();
- private void startService() throws TimeoutException {
- mService = new CsipSetCoordinatorService(mTargetContext);
- mService.start();
+ mService =
+ new CsipSetCoordinatorService(
+ mAdapterService, mLooper.getLooper(), mNativeInterface, mServiceFactory);
mService.setAvailable(true);
- }
- private void stopService() throws TimeoutException {
- mService.stop();
- mService = CsipSetCoordinatorService.getCsipSetCoordinatorService();
- Assert.assertNull(mService);
}
- /** Test getting CsipSetCoordinator Service */
- @Test
- public void testGetService() {
- Assert.assertEquals(mService, CsipSetCoordinatorService.getCsipSetCoordinatorService());
+ @After
+ public void tearDown() throws Exception {
+ mService.stop();
+ assertThat(CsipSetCoordinatorService.getCsipSetCoordinatorService()).isNull();
}
- /** Test stop CsipSetCoordinator Service */
@Test
- public void testStopService() {
- Assert.assertEquals(mService, CsipSetCoordinatorService.getCsipSetCoordinatorService());
-
- InstrumentationRegistry.getInstrumentation().runOnMainSync(mService::stop);
- InstrumentationRegistry.getInstrumentation().runOnMainSync(mService::start);
+ public void getService() {
+ assertThat(CsipSetCoordinatorService.getCsipSetCoordinatorService()).isEqualTo(mService);
}
- /** Test get/set policy for BluetoothDevice */
@Test
- public void testGetSetPolicy() {
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
- Assert.assertEquals(
- "Initial device policy",
- BluetoothProfile.CONNECTION_POLICY_UNKNOWN,
- mService.getConnectionPolicy(mTestDevice));
-
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
- Assert.assertEquals(
- "Setting device policy to POLICY_FORBIDDEN",
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
- mService.getConnectionPolicy(mTestDevice));
-
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- Assert.assertEquals(
- "Setting device policy to POLICY_ALLOWED",
- BluetoothProfile.CONNECTION_POLICY_ALLOWED,
- mService.getConnectionPolicy(mTestDevice));
+ public void getConnectionPolicy() {
+ for (int policy :
+ List.of(
+ CONNECTION_POLICY_UNKNOWN,
+ CONNECTION_POLICY_FORBIDDEN,
+ CONNECTION_POLICY_ALLOWED)) {
+ doReturn(policy).when(mDatabaseManager).getProfileConnectionPolicy(any(), anyInt());
+ assertThat(mService.getConnectionPolicy(mDevice)).isEqualTo(policy);
+ }
}
- /** Test if getProfileConnectionPolicy works after the service is stopped. */
@Test
- public void testGetPolicyAfterStopped() {
- mService.stop();
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
- Assert.assertEquals(
- "Initial device policy",
- BluetoothProfile.CONNECTION_POLICY_UNKNOWN,
- mService.getConnectionPolicy(mTestDevice));
+ public void canConnect_whenNotBonded_returnFalse() {
+ int badPolicyValue = 1024;
+ int badBondState = 42;
+ for (int bondState : List.of(BOND_NONE, BOND_BONDING, badBondState)) {
+ for (int policy :
+ List.of(
+ CONNECTION_POLICY_UNKNOWN,
+ CONNECTION_POLICY_FORBIDDEN,
+ CONNECTION_POLICY_ALLOWED,
+ badPolicyValue)) {
+ doReturn(bondState).when(mAdapterService).getBondState(any());
+ doReturn(policy).when(mDatabaseManager).getProfileConnectionPolicy(any(), anyInt());
+ assertThat(mService.okToConnect(mDevice)).isEqualTo(false);
+ }
+ }
}
- /** Test okToConnect method using various test cases */
@Test
- public void testOkToConnect() {
+ public void canConnect_whenBonded() {
int badPolicyValue = 1024;
- int badBondState = 42;
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_NONE,
- BluetoothProfile.CONNECTION_POLICY_UNKNOWN,
- false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_NONE,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
- false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_NONE,
- BluetoothProfile.CONNECTION_POLICY_ALLOWED,
- false);
- testOkToConnectCase(mTestDevice, BluetoothDevice.BOND_NONE, badPolicyValue, false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_BONDING,
- BluetoothProfile.CONNECTION_POLICY_UNKNOWN,
- false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_BONDING,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
- false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_BONDING,
- BluetoothProfile.CONNECTION_POLICY_ALLOWED,
- false);
- testOkToConnectCase(mTestDevice, BluetoothDevice.BOND_BONDING, badPolicyValue, false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_BONDED,
- BluetoothProfile.CONNECTION_POLICY_UNKNOWN,
- true);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_BONDED,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN,
- false);
- testOkToConnectCase(
- mTestDevice,
- BluetoothDevice.BOND_BONDED,
- BluetoothProfile.CONNECTION_POLICY_ALLOWED,
- true);
- testOkToConnectCase(mTestDevice, BluetoothDevice.BOND_BONDED, badPolicyValue, false);
- testOkToConnectCase(
- mTestDevice, badBondState, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false);
- testOkToConnectCase(
- mTestDevice, badBondState, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false);
- testOkToConnectCase(
- mTestDevice, badBondState, BluetoothProfile.CONNECTION_POLICY_ALLOWED, false);
- testOkToConnectCase(mTestDevice, badBondState, badPolicyValue, false);
+ doReturn(BOND_BONDED).when(mAdapterService).getBondState(any());
+
+ for (int policy : List.of(CONNECTION_POLICY_FORBIDDEN, badPolicyValue)) {
+ doReturn(policy).when(mDatabaseManager).getProfileConnectionPolicy(any(), anyInt());
+ assertThat(mService.okToConnect(mDevice)).isEqualTo(false);
+ }
+ for (int policy : List.of(CONNECTION_POLICY_UNKNOWN, CONNECTION_POLICY_ALLOWED)) {
+ doReturn(policy).when(mDatabaseManager).getProfileConnectionPolicy(any(), anyInt());
+ assertThat(mService.okToConnect(mDevice)).isEqualTo(true);
+ }
}
/** Test that call to groupLockSet method calls corresponding native interface method */
@Test
- public void testGroupLockSetNative() {
+ public void testGroupLockSetNative() throws RemoteException {
int group_id = 0x01;
int group_size = 0x01;
long uuidLsb = 0x01;
long uuidMsb = 0x01;
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onDeviceAvailable(
- any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong());
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice), group_id, group_size, 1, uuidLsb, uuidMsb);
- Assert.assertFalse(mService.isGroupLocked(group_id));
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice), group_id, group_size, 1, uuidLsb, uuidMsb);
+ assertThat(mService.isGroupLocked(group_id)).isFalse();
UUID lock_uuid = mService.lockGroup(group_id, mCsipSetCoordinatorLockCallback);
- Assert.assertNotNull(lock_uuid);
- verify(mCsipSetCoordinatorNativeInterface).groupLockSet(eq(group_id), eq(true));
- Assert.assertTrue(mService.isGroupLocked(group_id));
-
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onGroupLockChanged(anyInt(), anyBoolean(), anyInt());
- mCsipSetCoordinatorNativeInterface.onGroupLockChanged(
+ assertThat(lock_uuid).isNotNull();
+ verify(mNativeInterface).groupLockSet(eq(group_id), eq(true));
+ assertThat(mService.isGroupLocked(group_id)).isTrue();
+
+ mNativeCallback.onGroupLockChanged(
group_id, true, IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_SUCCESS);
- try {
- verify(mCsipSetCoordinatorLockCallback)
- .onGroupLockSet(group_id, BluetoothStatusCodes.SUCCESS, true);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ verify(mCsipSetCoordinatorLockCallback)
+ .onGroupLockSet(group_id, BluetoothStatusCodes.SUCCESS, true);
mService.unlockGroup(lock_uuid);
- verify(mCsipSetCoordinatorNativeInterface).groupLockSet(eq(group_id), eq(false));
+ verify(mNativeInterface).groupLockSet(eq(group_id), eq(false));
- mCsipSetCoordinatorNativeInterface.onGroupLockChanged(
+ mNativeCallback.onGroupLockChanged(
group_id, false, IBluetoothCsipSetCoordinator.CSIS_GROUP_LOCK_SUCCESS);
- Assert.assertFalse(mService.isGroupLocked(group_id));
+ assertThat(mService.isGroupLocked(group_id)).isFalse();
- try {
- verify(mCsipSetCoordinatorLockCallback)
- .onGroupLockSet(group_id, BluetoothStatusCodes.SUCCESS, false);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ verify(mCsipSetCoordinatorLockCallback)
+ .onGroupLockSet(group_id, BluetoothStatusCodes.SUCCESS, false);
}
/** Test that call to groupLockSet method calls corresponding native interface method */
@Test
- public void testGroupExclusiveLockSet() {
+ public void testGroupExclusiveLockSet() throws RemoteException {
int group_id = 0x01;
int group_size = 0x01;
long uuidLsb = 0x01;
long uuidMsb = 0x01;
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onDeviceAvailable(
- any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong());
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice), group_id, group_size, 1, uuidLsb, uuidMsb);
- Assert.assertFalse(mService.isGroupLocked(group_id));
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice), group_id, group_size, 1, uuidLsb, uuidMsb);
+ assertThat(mService.isGroupLocked(group_id)).isFalse();
UUID lock_uuid = mService.lockGroup(group_id, mCsipSetCoordinatorLockCallback);
- verify(mCsipSetCoordinatorNativeInterface).groupLockSet(eq(group_id), eq(true));
- Assert.assertNotNull(lock_uuid);
- Assert.assertTrue(mService.isGroupLocked(group_id));
+ verify(mNativeInterface).groupLockSet(eq(group_id), eq(true));
+ assertThat(lock_uuid).isNotNull();
+ assertThat(mService.isGroupLocked(group_id)).isTrue();
lock_uuid = mService.lockGroup(group_id, mCsipSetCoordinatorLockCallback);
- verify(mCsipSetCoordinatorNativeInterface).groupLockSet(eq(group_id), eq(true));
-
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onGroupLockChanged(anyInt(), anyBoolean(), anyInt());
-
- try {
- verify(mCsipSetCoordinatorLockCallback)
- .onGroupLockSet(
- group_id, BluetoothStatusCodes.ERROR_CSIP_GROUP_LOCKED_BY_OTHER, true);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- Assert.assertNull(lock_uuid);
+ verify(mNativeInterface).groupLockSet(eq(group_id), eq(true));
+
+ verify(mCsipSetCoordinatorLockCallback)
+ .onGroupLockSet(
+ group_id, BluetoothStatusCodes.ERROR_CSIP_GROUP_LOCKED_BY_OTHER, true);
+ assertThat(lock_uuid).isNull();
}
- /** Test that an outgoing connection to device that does not have MICS UUID is rejected */
@Test
- public void testOutgoingConnectMissingUuid() {
- // Update the device policy so okToConnect() returns true
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- doReturn(true).when(mCsipSetCoordinatorNativeInterface).connect(any(BluetoothDevice.class));
- doReturn(true).when(mCsipSetCoordinatorNativeInterface).connect(any(BluetoothDevice.class));
-
- // Return No UUID
+ public void connectToDevice_whenUuidIsMissing_returnFalse() {
doReturn(new ParcelUuid[] {})
.when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- // Send a connect request
- Assert.assertFalse("Connect expected to fail", mService.connect(mTestDevice));
+ assertThat(mService.connect(mDevice)).isFalse();
}
- /** Test that an outgoing connection to device that have MICS UUID is successful */
@Test
- public void testOutgoingConnectExistingUuid() {
- // Update the device policy so okToConnect() returns true
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- doReturn(true).when(mCsipSetCoordinatorNativeInterface).connect(any(BluetoothDevice.class));
- doReturn(true)
- .when(mCsipSetCoordinatorNativeInterface)
- .disconnect(any(BluetoothDevice.class));
-
- doReturn(new ParcelUuid[] {BluetoothUuid.COORDINATED_SET})
- .when(mAdapterService)
- .getRemoteUuids(any(BluetoothDevice.class));
+ public void connectToDevice_whenPolicyForbid_returnFalse() {
+ doReturn(CONNECTION_POLICY_FORBIDDEN)
+ .when(mDatabaseManager)
+ .getProfileConnectionPolicy(any(), anyInt());
- // Send a connect request
- Assert.assertTrue("Connect expected to succeed", mService.connect(mTestDevice));
-
- TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice));
+ assertThat(mService.connect(mDevice)).isFalse();
}
- /** Test that an outgoing connection to device with POLICY_FORBIDDEN is rejected */
@Test
- public void testOutgoingConnectPolicyForbidden() {
- doReturn(true).when(mCsipSetCoordinatorNativeInterface).connect(any(BluetoothDevice.class));
- doReturn(true)
- .when(mCsipSetCoordinatorNativeInterface)
- .disconnect(any(BluetoothDevice.class));
-
- // Set the device policy to POLICY_FORBIDDEN so connect() should fail
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
-
- // Send a connect request
- Assert.assertFalse("Connect expected to fail", mService.connect(mTestDevice));
- }
+ public void outgoingConnect_whenTimeOut_isDisconnected() {
+ assertThat(mService.connect(mDevice)).isTrue();
+ mLooper.dispatchAll();
- /** Test that an outgoing connection times out */
- @Test
- public void testOutgoingConnectTimeout() {
- // Update the device policy so okToConnect() returns true
- when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager);
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- doReturn(true).when(mCsipSetCoordinatorNativeInterface).connect(any(BluetoothDevice.class));
- doReturn(true)
- .when(mCsipSetCoordinatorNativeInterface)
- .disconnect(any(BluetoothDevice.class));
-
- // Send a connect request
- Assert.assertTrue("Connect failed", mService.connect(mTestDevice));
-
- // Verify the connection state broadcast, and that we are in Connecting state
- verifyConnectionStateIntent(
- TIMEOUT_MS,
- mTestDevice,
- BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTED);
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mTestDevice));
-
- // Verify the connection state broadcast, and that we are in Disconnected state
- verifyConnectionStateIntent(
- CsipSetCoordinatorStateMachine.sConnectTimeoutMs * 2,
- mTestDevice,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
- Assert.assertEquals(
- BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mTestDevice));
+ verifyConnectionStateIntent(STATE_CONNECTING, STATE_DISCONNECTED);
+
+ mLooper.moveTimeForward(CsipSetCoordinatorStateMachine.sConnectTimeoutMs);
+ mLooper.dispatchAll();
+
+ verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING);
}
- /** Test that native callback generates proper intent. */
@Test
- public void testStackEventDeviceAvailable() {
+ public void deviceAvailable_withDifferentRank_areOrdered() {
int group_id = 0x01;
int group_size = 0x03;
long uuidLsb = 0x01;
long uuidMsb = 0x01;
UUID uuid = new UUID(uuidMsb, uuidLsb);
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onDeviceAvailable(
- any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong());
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
-
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(
- BluetoothCsipSetCoordinator.ACTION_CSIS_DEVICE_AVAILABLE, intent.getAction());
- Assert.assertEquals(mTestDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(
- group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1));
- Assert.assertEquals(
- group_size,
- intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_SIZE, -1));
- Assert.assertEquals(
- uuid,
- intent.getSerializableExtra(
- BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID));
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
+
+ verifyOrderedIntentSent(
+ hasAction(ACTION_CSIS_DEVICE_AVAILABLE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, group_id),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_SIZE, group_size),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID, uuid));
// Another device with the highest rank
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice2), group_id, group_size, 0x01, uuidLsb, uuidMsb);
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice2), group_id, group_size, 0x01, uuidLsb, uuidMsb);
+ verifyOrderedIntentSent(
+ hasAction(ACTION_CSIS_DEVICE_AVAILABLE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice2),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, group_id),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_SIZE, group_size),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID, uuid));
// Yet another device with the lowest rank
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice3), group_id, group_size, 0x03, uuidLsb, uuidMsb);
-
- // Verify if the list of devices is sorted, with the lowest rank value devices first
- List<BluetoothDevice> devices = mService.getGroupDevicesOrdered(group_id);
- Assert.assertEquals(0, devices.indexOf(mTestDevice2));
- Assert.assertEquals(1, devices.indexOf(mTestDevice));
- Assert.assertEquals(2, devices.indexOf(mTestDevice3));
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice3), group_id, group_size, 0x03, uuidLsb, uuidMsb);
+ verifyOrderedIntentSent(
+ hasAction(ACTION_CSIS_DEVICE_AVAILABLE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice3),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, group_id),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_SIZE, group_size),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID, uuid));
+
+ assertThat(mService.getGroupDevicesOrdered(group_id))
+ .containsExactly(mDevice2, mDevice, mDevice3)
+ .inOrder();
}
/** Test that native callback generates proper intent after group connected. */
@Test
- public void testStackEventSetMemberAvailableAfterGroupConnected() {
+ public void nativeCallback_afterGroupConnected_generateIntent() {
int group_id = 0x01;
int group_size = 0x02;
long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits();
long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits();
- // Make sure to use real methods when needed below
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onDeviceAvailable(
- any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong());
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onConnectionStateChanged(any(byte[].class), anyInt());
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onSetMemberAvailable(any(byte[].class), anyInt());
-
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
- mCsipSetCoordinatorNativeInterface.onConnectionStateChanged(
- getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED);
+ mNativeCallback.onConnectionStateChanged(getByteAddress(mDevice), STATE_CONNECTED);
// Comes from state machine
- mService.connectionStateChanged(
- mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
-
- mCsipSetCoordinatorNativeInterface.onSetMemberAvailable(
- getByteAddress(mTestDevice2), group_id);
-
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2));
- Assert.assertNotNull(intent);
- Assert.assertEquals(
- BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction());
- Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(
- group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1));
+ mService.connectionStateChanged(mDevice, STATE_CONNECTING, STATE_CONNECTED);
+
+ mNativeCallback.onSetMemberAvailable(getByteAddress(mDevice2), group_id);
+
+ verifyOrderedIntentSent(
+ hasAction(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice2),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, group_id));
}
/** Test that native callback generates proper intent before group connected. */
@@ -565,42 +359,24 @@ public class CsipSetCoordinatorServiceTest {
long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits();
long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits();
- // Make sure to use real methods when needed below
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onDeviceAvailable(
- any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong());
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onSetMemberAvailable(any(byte[].class), anyInt());
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onConnectionStateChanged(any(byte[].class), anyInt());
-
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
+ verifyOrderedIntentSent(hasAction(ACTION_CSIS_DEVICE_AVAILABLE));
- mCsipSetCoordinatorNativeInterface.onConnectionStateChanged(
- getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED);
+ mNativeCallback.onConnectionStateChanged(getByteAddress(mDevice), STATE_CONNECTED);
+ // verifyConnectionStateIntent(STATE_CONNECTED, STATE_DISCONNECTED);
- mCsipSetCoordinatorNativeInterface.onSetMemberAvailable(
- getByteAddress(mTestDevice2), group_id);
+ mNativeCallback.onSetMemberAvailable(getByteAddress(mDevice2), group_id);
- Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2));
- Assert.assertNull(intent);
+ mInOrder.verify(mAdapterService, never()).sendOrderedBroadcast(any(), any());
// Comes from state machine
- mService.connectionStateChanged(
- mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
+ mService.connectionStateChanged(mDevice, STATE_CONNECTING, STATE_CONNECTED);
- intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2));
- Assert.assertNotNull(intent);
-
- Assert.assertEquals(
- BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction());
- Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(
- group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1));
+ verifyOrderedIntentSent(
+ hasAction(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice2),
+ hasExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, group_id));
}
/**
@@ -614,125 +390,76 @@ public class CsipSetCoordinatorServiceTest {
long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits();
long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits();
- doCallRealMethod()
- .when(mCsipSetCoordinatorNativeInterface)
- .onDeviceAvailable(
- any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong());
- when(mLeAudioService.getConnectionPolicy(any()))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ doReturn(CONNECTION_POLICY_FORBIDDEN).when(mLeAudioService).getConnectionPolicy(any());
// Make first set device available and connected
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
- mService.connectionStateChanged(
- mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);
+ mService.connectionStateChanged(mDevice, STATE_CONNECTING, STATE_CONNECTED);
// Another device with the highest rank
- mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
- getByteAddress(mTestDevice2), group_id, group_size, 0x01, uuidLsb, uuidMsb);
+ mNativeCallback.onDeviceAvailable(
+ getByteAddress(mDevice2), group_id, group_size, 0x01, uuidLsb, uuidMsb);
// When LEA is FORBIDDEN, verify we don't disable CSIP until all set devices are available
verify(mDatabaseManager, never())
.setProfileConnectionPolicy(
- mTestDevice,
+ mDevice,
BluetoothProfile.CSIP_SET_COORDINATOR,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ CONNECTION_POLICY_FORBIDDEN);
verify(mDatabaseManager, never())
.setProfileConnectionPolicy(
- mTestDevice2,
+ mDevice2,
BluetoothProfile.CSIP_SET_COORDINATOR,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ CONNECTION_POLICY_FORBIDDEN);
// Mark the second device as connected
- mService.connectionStateChanged(
- mTestDevice2, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
+ mService.connectionStateChanged(mDevice2, STATE_CONNECTING, STATE_CONNECTED);
// When LEA is FORBIDDEN, verify we disable CSIP once all set devices are available
verify(mDatabaseManager)
.setProfileConnectionPolicy(
- mTestDevice,
+ mDevice,
BluetoothProfile.CSIP_SET_COORDINATOR,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ CONNECTION_POLICY_FORBIDDEN);
verify(mDatabaseManager)
.setProfileConnectionPolicy(
- mTestDevice2,
+ mDevice2,
BluetoothProfile.CSIP_SET_COORDINATOR,
- BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ CONNECTION_POLICY_FORBIDDEN);
}
@Test
public void testDump_doesNotCrash() {
- // Update the device policy so okToConnect() returns true
- when(mDatabaseManager.getProfileConnectionPolicy(
- mTestDevice, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- doReturn(true).when(mCsipSetCoordinatorNativeInterface).connect(any(BluetoothDevice.class));
- doReturn(true)
- .when(mCsipSetCoordinatorNativeInterface)
- .disconnect(any(BluetoothDevice.class));
- doReturn(new ParcelUuid[] {BluetoothUuid.COORDINATED_SET})
- .when(mAdapterService)
- .getRemoteUuids(any(BluetoothDevice.class));
// add state machines for testing dump()
- mService.connect(mTestDevice);
-
- TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice));
+ mService.connect(mDevice);
mService.dump(new StringBuilder());
}
- /** Helper function to test ConnectionStateIntent() method */
- private void verifyConnectionStateIntent(
- int timeoutMs, BluetoothDevice device, int newState, int prevState) {
- Intent intent = TestUtils.waitForIntent(timeoutMs, mIntentQueue.get(device));
- Assert.assertNotNull(intent);
- Assert.assertEquals(
- BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED,
- intent.getAction());
- Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(newState, intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
- Assert.assertEquals(
- prevState, intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1));
- }
-
- /** Helper function to test okToConnect() method */
- private void testOkToConnectCase(
- BluetoothDevice device, int bondState, int policy, boolean expected) {
- doReturn(bondState).when(mAdapterService).getBondState(device);
- when(mDatabaseManager.getProfileConnectionPolicy(
- device, BluetoothProfile.CSIP_SET_COORDINATOR))
- .thenReturn(policy);
- Assert.assertEquals(expected, mService.okToConnect(device));
+ private void verifyConnectionStateIntent(int newState, int prevState) {
+ verifyIntentSent(
+ hasAction(BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice),
+ hasExtra(EXTRA_STATE, newState),
+ hasExtra(EXTRA_PREVIOUS_STATE, prevState));
+ assertThat(mService.getConnectionState(mDevice)).isEqualTo(newState);
}
/** Helper function to get byte array for a device address */
private byte[] getByteAddress(BluetoothDevice device) {
- if (device == null) {
- return Utils.getBytesFromAddress("00:00:00:00:00:00");
- }
return Utils.getBytesFromAddress(device.getAddress());
}
- private class CsipSetCoordinatorIntentReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- try {
- /* Ignore intent when service is inactive */
- if (mService == null) {
- return;
- }
-
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- // Use first device's queue in case of no device in the intent
- if (device == null) {
- device = mTestDevice;
- }
- LinkedBlockingQueue<Intent> queue = mIntentQueue.get(device);
- Assert.assertNotNull(queue);
- queue.put(intent);
- } catch (InterruptedException e) {
- Assert.fail("Cannot add Intent to the queue: " + e.getMessage());
- }
- }
+ @SafeVarargs
+ private void verifyIntentSent(Matcher<Intent>... matchers) {
+ mInOrder.verify(mAdapterService)
+ .sendBroadcast(MockitoHamcrest.argThat(AllOf.allOf(matchers)), any());
+ }
+
+ @SafeVarargs
+ private void verifyOrderedIntentSent(Matcher<Intent>... matchers) {
+ mInOrder.verify(mAdapterService)
+ .sendOrderedBroadcast(MockitoHamcrest.argThat(AllOf.allOf(matchers)), any());
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachineTest.java
index 3890c8d15b..8502c240d1 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorStateMachineTest.java
@@ -22,6 +22,8 @@ import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -277,10 +279,10 @@ public class CsipSetCoordinatorStateMachineTest {
@Test
public void testIsConnected() {
- Assert.assertFalse(mStateMachine.isConnected());
+ assertThat(mStateMachine.isConnected()).isFalse();
initToConnectedState();
- Assert.assertTrue(mStateMachine.isConnected());
+ assertThat(mStateMachine.isConnected()).isTrue();
}
@Test
@@ -396,9 +398,10 @@ public class CsipSetCoordinatorStateMachineTest {
initToConnectingState();
mStateMachine.sendMessage(CsipSetCoordinatorStateMachine.CONNECT);
TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertTrue(
- mStateMachine.doesSuperHaveDeferredMessages(
- CsipSetCoordinatorStateMachine.CONNECT));
+ assertThat(
+ mStateMachine.doesSuperHaveDeferredMessages(
+ CsipSetCoordinatorStateMachine.CONNECT))
+ .isTrue();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java
index 0d9f7bee9e..2b34af7690 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.after;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.bluetooth.BluetoothAdapter;
@@ -67,12 +68,15 @@ public class DistanceMeasurementManagerTest {
private static final String IDENTITY_ADDRESS = "00:01:02:03:04:05";
private static final int RSSI_FREQUENCY_LOW = 3000;
+ private static final int CS_FREQUENCY_LOW = 5000;
@Before
public void setUp() throws Exception {
doReturn(mPackageManager).when(mAdapterService).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(any());
+ doReturn(true).when(mAdapterService).isLeChannelSoundingSupported();
doReturn(IDENTITY_ADDRESS).when(mAdapterService).getIdentityAddress(IDENTITY_ADDRESS);
+ doReturn(true).when(mAdapterService).isConnected(any());
DistanceMeasurementNativeInterface.setInstance(mDistanceMeasurementNativeInterface);
mDistanceMeasurementManager = new DistanceMeasurementManager(mAdapterService);
mUuid = UUID.randomUUID();
@@ -160,6 +164,67 @@ public class DistanceMeasurementManagerTest {
}
@Test
+ public void testCsStartFailForNoBondedBLE() throws RemoteException {
+ doReturn(BluetoothDevice.BOND_NONE).when(mAdapterService).getBondState(any());
+ DistanceMeasurementParams params =
+ new DistanceMeasurementParams.Builder(mDevice)
+ .setDurationSeconds(1000)
+ .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW)
+ .setMethodId(
+ DistanceMeasurementMethod
+ .DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING)
+ .build();
+ mDistanceMeasurementManager.startDistanceMeasurement(mUuid, params, mCallback);
+
+ verify(mDistanceMeasurementNativeInterface, never())
+ .startDistanceMeasurement(
+ IDENTITY_ADDRESS,
+ CS_FREQUENCY_LOW,
+ DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING);
+ verify(mCallback).onStartFail(mDevice, BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED);
+ }
+
+ @Test
+ public void testCsStartSuccessForBondedBLE() throws RemoteException {
+ doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService).getBondState(any());
+ DistanceMeasurementParams params =
+ new DistanceMeasurementParams.Builder(mDevice)
+ .setDurationSeconds(1000)
+ .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW)
+ .setMethodId(
+ DistanceMeasurementMethod
+ .DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING)
+ .build();
+ mDistanceMeasurementManager.startDistanceMeasurement(mUuid, params, mCallback);
+
+ verify(mDistanceMeasurementNativeInterface)
+ .startDistanceMeasurement(
+ IDENTITY_ADDRESS,
+ CS_FREQUENCY_LOW,
+ DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING);
+
+ mDistanceMeasurementManager.onDistanceMeasurementStarted(
+ IDENTITY_ADDRESS,
+ DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING);
+ mDistanceMeasurementManager.onDistanceMeasurementResult(
+ IDENTITY_ADDRESS,
+ 100,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING);
+ ArgumentCaptor<DistanceMeasurementResult> result =
+ ArgumentCaptor.forClass(DistanceMeasurementResult.class);
+
+ verify(mCallback).onResult(eq(mDevice), result.capture());
+ assertThat(result.getValue().getResultMeters()).isEqualTo(1.00);
+ }
+
+ @Test
public void testHandleRssiStopped() throws RemoteException {
DistanceMeasurementParams params =
new DistanceMeasurementParams.Builder(mDevice)
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java
index c652787209..8750c283ac 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java
@@ -36,6 +36,7 @@ import android.bluetooth.le.DistanceMeasurementMethod;
import android.bluetooth.le.DistanceMeasurementParams;
import android.bluetooth.le.IDistanceMeasurementCallback;
import android.bluetooth.le.PeriodicAdvertisingParameters;
+import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.Context;
import android.content.res.Resources;
@@ -102,6 +103,8 @@ public class GattServiceTest {
private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
private final AttributionSource mAttributionSource = mAdapter.getAttributionSource();
private final Context mContext = InstrumentationRegistry.getTargetContext();
+ private final CompanionDeviceManager mCompanionDeviceManager =
+ mContext.getSystemService(CompanionDeviceManager.class);
private MockContentResolver mMockContentResolver;
@@ -141,6 +144,11 @@ public class GattServiceTest {
mAdapterService, Context.LOCATION_SERVICE, LocationManager.class);
TestUtils.mockGetSystemService(
mAdapterService, Context.ACTIVITY_SERVICE, ActivityManager.class);
+ TestUtils.mockGetSystemService(
+ mAdapterService,
+ Context.COMPANION_DEVICE_SERVICE,
+ CompanionDeviceManager.class,
+ mCompanionDeviceManager);
mBtCompanionManager = new CompanionManager(mAdapterService, null);
doReturn(mBtCompanionManager).when(mAdapterService).getCompanionManager();
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 27ed8219f5..a1095a6c59 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
@@ -16,6 +16,8 @@
package com.android.bluetooth.hfp;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -153,7 +155,7 @@ public class HeadsetServiceTest {
// Mock methods in HeadsetObjectsFactory
doAnswer(
invocation -> {
- Assert.assertNotNull(mCurrentDevice);
+ assertThat(mCurrentDevice).isNotNull();
final HeadsetStateMachine stateMachine =
mock(HeadsetStateMachine.class);
doReturn(BluetoothProfile.STATE_DISCONNECTED)
@@ -181,7 +183,7 @@ public class HeadsetServiceTest {
mHeadsetService.stop();
HeadsetNativeInterface.setInstance(null);
mHeadsetService = HeadsetService.getHeadsetService();
- Assert.assertNull(mHeadsetService);
+ assertThat(mHeadsetService).isNull();
mStateMachines.clear();
mCurrentDevice = null;
HeadsetObjectsFactory.setInstanceForTesting(null);
@@ -284,7 +286,7 @@ public class HeadsetServiceTest {
any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -309,7 +311,7 @@ public class HeadsetServiceTest {
Assert.assertEquals(
Collections.singletonList(mCurrentDevice), mHeadsetService.getConnectedDevices());
// 2nd connection attempt will fail
- Assert.assertFalse(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isFalse();
// Verify makeStateMachine is only called once
verify(mObjectsFactory).makeStateMachine(any(), any(), any(), any(), any(), any());
// Verify CONNECT is only sent once
@@ -424,7 +426,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -465,7 +467,7 @@ public class HeadsetServiceTest {
}
// Connect the next device will fail
mCurrentDevice = TestUtils.getTestDevice(mAdapter, MAX_HEADSET_CONNECTIONS);
- Assert.assertFalse(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isFalse();
// Though connection failed, a new state machine is still lazily created for the device
verify(mObjectsFactory, times(MAX_HEADSET_CONNECTIONS + 1))
.makeStateMachine(
@@ -494,7 +496,7 @@ public class HeadsetServiceTest {
any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -520,7 +522,7 @@ public class HeadsetServiceTest {
BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTED);
// Test connect audio - set the device first as the active device
- Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isTrue();
Assert.assertEquals(
BluetoothStatusCodes.SUCCESS, mHeadsetService.connectAudio(mCurrentDevice));
verify(mStateMachines.get(mCurrentDevice))
@@ -560,7 +562,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -614,7 +616,7 @@ public class HeadsetServiceTest {
BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE,
mHeadsetService.connectAudio(mCurrentDevice));
// Should succeed after setActiveDevice()
- Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isTrue();
Assert.assertEquals(
BluetoothStatusCodes.SUCCESS, mHeadsetService.connectAudio(mCurrentDevice));
verify(mStateMachines.get(mCurrentDevice))
@@ -661,7 +663,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -715,7 +717,7 @@ public class HeadsetServiceTest {
BluetoothDevice firstDevice = connectedDevices.get(0);
BluetoothDevice secondDevice = connectedDevices.get(1);
// Set the first device as the active device
- Assert.assertTrue(mHeadsetService.setActiveDevice(firstDevice));
+ assertThat(mHeadsetService.setActiveDevice(firstDevice)).isTrue();
Assert.assertEquals(
BluetoothStatusCodes.SUCCESS, mHeadsetService.connectAudio(firstDevice));
verify(mStateMachines.get(firstDevice))
@@ -764,7 +766,7 @@ public class HeadsetServiceTest {
.getBondedDevices();
for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -817,7 +819,7 @@ public class HeadsetServiceTest {
}
// Try to connect audio
BluetoothDevice firstDevice = connectedDevices.get(0);
- Assert.assertTrue(mHeadsetService.setActiveDevice(firstDevice));
+ assertThat(mHeadsetService.setActiveDevice(firstDevice)).isTrue();
Assert.assertEquals(BluetoothStatusCodes.SUCCESS, mHeadsetService.connectAudio());
verify(mStateMachines.get(firstDevice))
.sendMessage(HeadsetStateMachine.CONNECT_AUDIO, firstDevice);
@@ -845,7 +847,7 @@ public class HeadsetServiceTest {
any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -920,7 +922,7 @@ public class HeadsetServiceTest {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
final ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
// Connect one device
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -984,7 +986,7 @@ public class HeadsetServiceTest {
mPhoneState, headsetCallState, ASYNC_CALL_TIMEOUT_MILLIS);
// Set the device first as the active device
- Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isTrue();
// Change phone state
headsetCallState.mCallState = HeadsetHalConstants.CALL_STATE_ALERTING;
mHeadsetService.phoneStateChanged(
@@ -1023,7 +1025,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -1073,7 +1075,7 @@ public class HeadsetServiceTest {
mCurrentDevice,
BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_CONNECTED);
- Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isTrue();
}
// Change phone state
mHeadsetService.phoneStateChanged(
@@ -1104,7 +1106,7 @@ public class HeadsetServiceTest {
any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -1139,7 +1141,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
for (int i = 2; i >= 0; i--) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
verify(mObjectsFactory)
.makeStateMachine(
mCurrentDevice,
@@ -1171,7 +1173,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
for (int i = 0; i < 2; i++) {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
when(mStateMachines.get(mCurrentDevice).getConnectionState())
.thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -1182,23 +1184,23 @@ public class HeadsetServiceTest {
BluetoothDevice otherDevice = TestUtils.getTestDevice(mAdapter, 1);
// Test whether active device been removed after enable silence mode.
- Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isTrue();
Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
- Assert.assertTrue(mHeadsetService.setSilenceMode(mCurrentDevice, true));
- Assert.assertNull(mHeadsetService.getActiveDevice());
+ assertThat(mHeadsetService.setSilenceMode(mCurrentDevice, true)).isTrue();
+ assertThat(mHeadsetService.getActiveDevice()).isNull();
// Test whether active device been resumed after disable silence mode.
- Assert.assertTrue(mHeadsetService.setSilenceMode(mCurrentDevice, false));
+ assertThat(mHeadsetService.setSilenceMode(mCurrentDevice, false)).isTrue();
Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
// Test that active device should not be changed when silence a non-active device
- Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isTrue();
Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
- Assert.assertTrue(mHeadsetService.setSilenceMode(otherDevice, true));
+ assertThat(mHeadsetService.setSilenceMode(otherDevice, true)).isTrue();
Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
// Test that active device should not be changed when another device exits silence mode
- Assert.assertTrue(mHeadsetService.setSilenceMode(otherDevice, false));
+ assertThat(mHeadsetService.setSilenceMode(otherDevice, false)).isTrue();
Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
}
@@ -1211,17 +1213,17 @@ public class HeadsetServiceTest {
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
mHeadsetService.setForceScoAudio(false);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
when(mStateMachines.get(mCurrentDevice).getConnectionState())
.thenReturn(BluetoothProfile.STATE_CONNECTED);
- Assert.assertTrue(mHeadsetService.setActiveDevice(null));
+ assertThat(mHeadsetService.setActiveDevice(null)).isTrue();
when(mSystemInterface.isInCall()).thenReturn(true);
mHeadsetService.setAudioRouteAllowed(false);
// Test that active device should not be changed if audio is not allowed
- Assert.assertFalse(mHeadsetService.setActiveDevice(mCurrentDevice));
+ assertThat(mHeadsetService.setActiveDevice(mCurrentDevice)).isFalse();
Assert.assertEquals(null, mHeadsetService.getActiveDevice());
}
@@ -1240,19 +1242,17 @@ public class HeadsetServiceTest {
.thenReturn(null);
// No connected device
- Assert.assertTrue(mHeadsetService.getFallbackCandidates(mDatabaseManager).isEmpty());
+ assertThat(mHeadsetService.getFallbackCandidates(mDatabaseManager)).isEmpty();
// One connected device
addConnectedDeviceHelper(deviceA);
- Assert.assertTrue(
- mHeadsetService.getFallbackCandidates(mDatabaseManager).contains(deviceA));
+ assertThat(mHeadsetService.getFallbackCandidates(mDatabaseManager))
+ .containsExactly(deviceA);
// Two connected devices
addConnectedDeviceHelper(deviceB);
- Assert.assertTrue(
- mHeadsetService.getFallbackCandidates(mDatabaseManager).contains(deviceA));
- Assert.assertTrue(
- mHeadsetService.getFallbackCandidates(mDatabaseManager).contains(deviceB));
+ assertThat(mHeadsetService.getFallbackCandidates(mDatabaseManager))
+ .containsExactly(deviceA, deviceB);
}
@Test
@@ -1268,14 +1268,12 @@ public class HeadsetServiceTest {
// Has a connected watch device
addConnectedDeviceHelper(deviceWatch);
- Assert.assertTrue(mHeadsetService.getFallbackCandidates(mDatabaseManager).isEmpty());
+ assertThat(mHeadsetService.getFallbackCandidates(mDatabaseManager)).isEmpty();
// Two connected devices with one watch
addConnectedDeviceHelper(deviceRegular);
- Assert.assertFalse(
- mHeadsetService.getFallbackCandidates(mDatabaseManager).contains(deviceWatch));
- Assert.assertTrue(
- mHeadsetService.getFallbackCandidates(mDatabaseManager).contains(deviceRegular));
+ assertThat(mHeadsetService.getFallbackCandidates(mDatabaseManager))
+ .containsExactly(deviceRegular);
}
@Test
@@ -1284,7 +1282,7 @@ public class HeadsetServiceTest {
any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
- Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
+ assertThat(mHeadsetService.connect(mCurrentDevice)).isTrue();
when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
when(mStateMachines.get(mCurrentDevice).getConnectionState())
.thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -1325,7 +1323,7 @@ public class HeadsetServiceTest {
when(mDatabaseManager.getProfileConnectionPolicy(
any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
.thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
- Assert.assertTrue(mHeadsetService.connect(device));
+ assertThat(mHeadsetService.connect(device)).isTrue();
when(mStateMachines.get(device).getDevice()).thenReturn(device);
when(mStateMachines.get(device).getConnectionState())
.thenReturn(BluetoothProfile.STATE_CONNECTING);
@@ -1335,7 +1333,7 @@ public class HeadsetServiceTest {
.thenReturn(BluetoothProfile.STATE_CONNECTED);
Assert.assertEquals(
BluetoothProfile.STATE_CONNECTED, mHeadsetService.getConnectionState(device));
- Assert.assertTrue(mHeadsetService.getConnectedDevices().contains(device));
+ assertThat(mHeadsetService.getConnectedDevices()).contains(device);
}
/*
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 41c5ab614b..75dfc971a1 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
@@ -19,6 +19,8 @@ package com.android.bluetooth.hfp;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.media.audio.Flags.FLAG_DEPRECATE_STREAM_BT_SCO;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -1888,56 +1890,66 @@ public class HeadsetStateMachineTest {
// Commands that will be handled
int counter_ok = 0;
int counter_error = 0;
- Assert.assertTrue(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=?", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=?", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_ok))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_OK, 0);
- Assert.assertTrue(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "+ANDROID=SINKAUDIOPOLICY,1,1,1", mTestDevice));
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "+ANDROID=SINKAUDIOPOLICY,1,1,1", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_ok))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_OK, 0);
- Assert.assertTrue(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "+ANDROID=SINKAUDIOPOLICY,100,100,100", mTestDevice));
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "+ANDROID=SINKAUDIOPOLICY,100,100,100", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_ok))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_OK, 0);
- Assert.assertTrue(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "+ANDROID=SINKAUDIOPOLICY,1,2,3,4,5", mTestDevice));
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "+ANDROID=SINKAUDIOPOLICY,1,2,3,4,5", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_error))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
- Assert.assertTrue(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=1", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=1", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_error))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
- Assert.assertTrue(
- mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=1,2", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=1,2", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_error))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
- Assert.assertTrue(
- mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=1,2,3", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=1,2,3", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_error))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
- Assert.assertTrue(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "+ANDROID=1,2,3,4,5,6,7", mTestDevice));
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "+ANDROID=1,2,3,4,5,6,7", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(++counter_error))
.atResponseCode(mTestDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
// Commands with correct format but will not be handled
- Assert.assertFalse(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=", mTestDevice));
- Assert.assertFalse(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "+ANDROID: PROBE,1,\"`AB\"", mTestDevice));
- Assert.assertFalse(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "+ANDROID= PROBE,1,\"`AB\"", mTestDevice));
- Assert.assertFalse(
- mHeadsetStateMachine.checkAndProcessAndroidAt(
- "AT+ANDROID=PROBE,1,1,\"PQGHRSBCTU__\"", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=", mTestDevice))
+ .isFalse();
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "+ANDROID: PROBE,1,\"`AB\"", mTestDevice))
+ .isFalse();
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "+ANDROID= PROBE,1,\"`AB\"", mTestDevice))
+ .isFalse();
+ assertThat(
+ mHeadsetStateMachine.checkAndProcessAndroidAt(
+ "AT+ANDROID=PROBE,1,1,\"PQGHRSBCTU__\"", mTestDevice))
+ .isFalse();
// Incorrect format AT command
- Assert.assertFalse(
- mHeadsetStateMachine.checkAndProcessAndroidAt("RANDOM FORMAT", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("RANDOM FORMAT", mTestDevice))
+ .isFalse();
// Check no any AT result was sent for the failed ones
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(counter_ok))
@@ -1957,7 +1969,8 @@ public class HeadsetStateMachineTest {
@Test
public void testCheckAndProcessAndroidAt_replyAndroidAtFeatureRequest() {
// Commands that will be handled
- Assert.assertTrue(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=?", mTestDevice));
+ assertThat(mHeadsetStateMachine.checkAndProcessAndroidAt("+ANDROID=?", mTestDevice))
+ .isTrue();
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
.atResponseString(mTestDevice, "+ANDROID: (SINKAUDIOPOLICY)");
verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
@@ -1966,7 +1979,7 @@ public class HeadsetStateMachineTest {
/** A end to end test to validate received Android AT commands and processing */
@Test
- public void testCehckAndProcessAndroidAtFromStateMachine() {
+ public void testCheckAndProcessAndroidAtFromStateMachine() {
// setAudioPolicyMetadata is invoked in HeadsetStateMachine.init() so start from 1
int expectCallTimes = 1;
@@ -2000,22 +2013,22 @@ public class HeadsetStateMachineTest {
@Test
public void testProcessAndroidAtSinkAudioPolicy() {
// expected format
- Assert.assertTrue(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,0", mTestDevice));
- Assert.assertTrue(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,1", mTestDevice));
- Assert.assertTrue(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,1,0", mTestDevice));
- Assert.assertTrue(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,1,0,0", mTestDevice));
- Assert.assertTrue(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,1,1,1", mTestDevice));
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,0", mTestDevice)).isTrue();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,1", mTestDevice)).isTrue();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,1,0", mTestDevice)).isTrue();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,1,0,0", mTestDevice)).isTrue();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,1,1,1", mTestDevice)).isTrue();
// invalid format
- Assert.assertFalse(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0", mTestDevice));
- Assert.assertFalse(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0", mTestDevice));
- Assert.assertFalse(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,0,0", mTestDevice));
- Assert.assertFalse(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,NOT,INT,TYPE", mTestDevice));
- Assert.assertFalse(setSinkAudioPolicyArgs("RANDOM,VALUE-#$%,*(&^", mTestDevice));
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0", mTestDevice)).isFalse();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0", mTestDevice)).isFalse();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,0,0", mTestDevice)).isFalse();
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,NOT,INT,TYPE", mTestDevice)).isFalse();
+ assertThat(setSinkAudioPolicyArgs("RANDOM,VALUE-#$%,*(&^", mTestDevice)).isFalse();
// wrong device
BluetoothDevice device = mAdapter.getRemoteDevice("01:01:01:01:01:01");
- Assert.assertFalse(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,0", device));
+ assertThat(setSinkAudioPolicyArgs("SINKAUDIOPOLICY,0,0,0", device)).isFalse();
}
/** Test setting audio parameters according to received SWB event. SWB AptX is enabled. */
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetTestUtils.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetTestUtils.java
index 9093b8b5e0..e80048dafa 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetTestUtils.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetTestUtils.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.hfp;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothDevice;
@@ -38,7 +40,7 @@ public class HeadsetTestUtils {
*/
public static void verifyAudioStateBroadcast(
BluetoothDevice device, int toState, int fromState, Intent intent) {
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
Assert.assertEquals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED, intent.getAction());
Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(toState, intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
@@ -58,7 +60,7 @@ public class HeadsetTestUtils {
*/
public static void verifyConnectionStateBroadcast(
BluetoothDevice device, int toState, int fromState, Intent intent, boolean checkFlag) {
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
Assert.assertEquals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED, intent.getAction());
if (checkFlag) {
Assert.assertEquals(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, intent.getFlags());
@@ -94,7 +96,7 @@ public class HeadsetTestUtils {
*/
public static void verifyActiveDeviceChangedBroadcast(
BluetoothDevice device, Intent intent, boolean checkFlag) {
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
Assert.assertEquals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED, intent.getAction());
Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
if (checkFlag) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
index 945a99cd6b..3541670116 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
@@ -21,6 +21,8 @@ import static android.content.pm.PackageManager.FEATURE_WATCH;
import static com.android.bluetooth.hfpclient.HeadsetClientService.MAX_HFP_SCO_VOICE_CALL_VOLUME;
import static com.android.bluetooth.hfpclient.HeadsetClientService.MIN_HFP_SCO_VOICE_CALL_VOLUME;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
@@ -107,7 +109,7 @@ public class HeadsetClientServiceTest {
@Test
public void testInitialize() throws Exception {
startService();
- Assert.assertNotNull(HeadsetClientService.getHeadsetClientService());
+ assertThat(HeadsetClientService.getHeadsetClientService()).isNotNull();
}
@Ignore("b/260202548")
@@ -215,7 +217,7 @@ public class HeadsetClientServiceTest {
int amMax = 10;
Map<Integer, Integer> amToHfMap = new HashMap<>();
- Assert.assertTrue(amMax < MAX_HFP_SCO_VOICE_CALL_VOLUME);
+ assertThat(amMax).isLessThan(MAX_HFP_SCO_VOICE_CALL_VOLUME);
doReturn(amMax).when(mMockAudioManager).getStreamMaxVolume(anyInt());
doReturn(amMin).when(mMockAudioManager).getStreamMinVolume(anyInt());
@@ -245,7 +247,7 @@ public class HeadsetClientServiceTest {
int amMax = 20;
Map<Integer, Integer> hfToAmMap = new HashMap<>();
- Assert.assertTrue(amMax > MAX_HFP_SCO_VOICE_CALL_VOLUME);
+ assertThat(amMax).isGreaterThan(MAX_HFP_SCO_VOICE_CALL_VOLUME);
doReturn(amMax).when(mMockAudioManager).getStreamMaxVolume(anyInt());
doReturn(amMin).when(mMockAudioManager).getStreamMinVolume(anyInt());
@@ -272,7 +274,7 @@ public class HeadsetClientServiceTest {
private void stopServiceIfStarted() throws Exception {
if (mIsHeadsetClientServiceStarted) {
mService.stop();
- Assert.assertNull(HeadsetClientService.getHeadsetClientService());
+ assertThat(HeadsetClientService.getHeadsetClientService()).isNull();
}
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java
index a509da0730..fc33b519d7 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.hid;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -102,7 +104,6 @@ public class HidDeviceTest {
if (Looper.myLooper() == null) {
Looper.prepare();
}
- Assert.assertNotNull(Looper.myLooper());
TestUtils.setAdapterService(mAdapterService);
doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
@@ -147,7 +148,7 @@ public class HidDeviceTest {
public void tearDown() throws Exception {
mHidDeviceService.stop();
mHidDeviceService = HidDeviceService.getHidDeviceService();
- Assert.assertNull(mHidDeviceService);
+ assertThat(mHidDeviceService).isNull();
mTargetContext.unregisterReceiver(mConnectionStateChangedReceiver);
mConnectionStateChangedQueue.clear();
mCallbackQueue.clear();
@@ -172,7 +173,7 @@ public class HidDeviceTest {
private Intent waitForIntent(int timeoutMs, BlockingQueue<Intent> queue) {
try {
Intent intent = queue.poll(timeoutMs, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
return intent;
} catch (InterruptedException e) {
throw new AssertionError("Cannot obtain an Intent from the queue", e);
@@ -182,7 +183,7 @@ public class HidDeviceTest {
private void verifyConnectionStateIntent(
int timeoutMs, BluetoothDevice device, int newState, int prevState) {
Intent intent = waitForIntent(timeoutMs, mConnectionStateChangedQueue);
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
Assert.assertEquals(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED, intent.getAction());
Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(newState, intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
@@ -193,7 +194,7 @@ public class HidDeviceTest {
private void verifyCallback(int timeoutMs, int callbackType, BlockingQueue<Integer> queue) {
try {
Integer lastCallback = queue.poll(timeoutMs, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(lastCallback);
+ assertThat(lastCallback).isNotNull();
int lastCallbackType = lastCallback;
Assert.assertEquals(callbackType, lastCallbackType);
} catch (InterruptedException e) {
@@ -292,7 +293,7 @@ public class HidDeviceTest {
// Register app
BluetoothHidDeviceCallbackTestHelper helper = new BluetoothHidDeviceCallbackTestHelper();
- Assert.assertTrue(mHidDeviceService.registerApp(mSettings, null, null, helper));
+ assertThat(mHidDeviceService.registerApp(mSettings, null, null, helper)).isTrue();
verify(mHidDeviceNativeInterface)
.registerApp(
@@ -339,7 +340,7 @@ public class HidDeviceTest {
isNull(),
isNull());
BluetoothHidDeviceCallbackTestHelper helper = new BluetoothHidDeviceCallbackTestHelper();
- Assert.assertTrue(mHidDeviceService.registerApp(mSettings, null, null, helper));
+ assertThat(mHidDeviceService.registerApp(mSettings, null, null, helper)).isTrue();
// App registered
mHidDeviceService.onApplicationStateChangedFromNative(mTestDevice, true);
@@ -384,7 +385,7 @@ public class HidDeviceTest {
isNull(),
isNull());
BluetoothHidDeviceCallbackTestHelper helper = new BluetoothHidDeviceCallbackTestHelper();
- Assert.assertTrue(mHidDeviceService.registerApp(mSettings, null, null, helper));
+ assertThat(mHidDeviceService.registerApp(mSettings, null, null, helper)).isTrue();
// App registered
mHidDeviceService.onApplicationStateChangedFromNative(mTestDevice, true);
@@ -425,7 +426,7 @@ public class HidDeviceTest {
isNull(),
isNull());
BluetoothHidDeviceCallbackTestHelper helper = new BluetoothHidDeviceCallbackTestHelper();
- Assert.assertTrue(mHidDeviceService.registerApp(mSettings, null, null, helper));
+ assertThat(mHidDeviceService.registerApp(mSettings, null, null, helper)).isTrue();
// App registered
mHidDeviceService.onApplicationStateChangedFromNative(mTestDevice, true);
@@ -466,7 +467,7 @@ public class HidDeviceTest {
mHidDeviceService.onApplicationStateChangedFromNative(mTestDevice, true);
// Send a connect request
- Assert.assertTrue("Connect failed", mHidDeviceService.connect(mTestDevice));
+ assertThat(mHidDeviceService.connect(mTestDevice)).isTrue();
mHidDeviceService.onConnectStateChangedFromNative(
mTestDevice, HidDeviceService.HAL_CONN_STATE_CONNECTING);
@@ -493,14 +494,13 @@ public class HidDeviceTest {
mHidDeviceService.getConnectionState(mTestDevice));
// Verify the list of connected devices
- Assert.assertTrue(
- mHidDeviceService
- .getDevicesMatchingConnectionStates(
- new int[] {BluetoothProfile.STATE_CONNECTED})
- .contains(mTestDevice));
+ assertThat(
+ mHidDeviceService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED}))
+ .contains(mTestDevice);
// Send a disconnect request
- Assert.assertTrue("Disconnect failed", mHidDeviceService.disconnect(mTestDevice));
+ assertThat(mHidDeviceService.disconnect(mTestDevice)).isTrue();
mHidDeviceService.onConnectStateChangedFromNative(
mTestDevice, HidDeviceService.HAL_CONN_STATE_DISCONNECTING);
@@ -527,11 +527,10 @@ public class HidDeviceTest {
mHidDeviceService.getConnectionState(mTestDevice));
// Verify the list of connected devices
- Assert.assertFalse(
- mHidDeviceService
- .getDevicesMatchingConnectionStates(
- new int[] {BluetoothProfile.STATE_CONNECTED})
- .contains(mTestDevice));
+ assertThat(
+ mHidDeviceService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED}))
+ .doesNotContain(mTestDevice);
// Unregister app
doReturn(true).when(mHidDeviceNativeInterface).unregisterApp();
@@ -568,7 +567,7 @@ public class HidDeviceTest {
// Register app
BluetoothHidDeviceCallbackTestHelper helper = new BluetoothHidDeviceCallbackTestHelper();
- Assert.assertTrue(mHidDeviceService.registerApp(mSettings, null, null, helper));
+ assertThat(mHidDeviceService.registerApp(mSettings, null, null, helper)).isTrue();
verify(mHidDeviceNativeInterface)
.registerApp(
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
index a13f676bf2..7cf714c142 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
@@ -15,6 +15,8 @@
*/
package com.android.bluetooth.hid;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -77,12 +79,12 @@ public class HidHostServiceTest {
mService.cleanup();
HidHostNativeInterface.setInstance(null);
mService = HidHostService.getHidHostService();
- Assert.assertNull(mService);
+ assertThat(mService).isNull();
}
@Test
public void testInitialize() {
- Assert.assertNotNull(HidHostService.getHidHostService());
+ assertThat(HidHostService.getHidHostService()).isNotNull();
}
/** Test okToConnect method using various test cases */
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/ContentControlIdKeeperTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/ContentControlIdKeeperTest.java
index 572eb95e51..fdd2aacad0 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/ContentControlIdKeeperTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/ContentControlIdKeeperTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.le_audio;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothLeAudio;
@@ -68,7 +70,7 @@ public class ContentControlIdKeeperTest {
Map<ParcelUuid, Pair<Integer, Integer>> uuidToCcidContextPair =
ContentControlIdKeeper.getUuidToCcidContextPairMap();
Assert.assertEquals(expectedListSize, uuidToCcidContextPair.size());
- Assert.assertTrue(uuidToCcidContextPair.containsKey(uuid));
+ assertThat(uuidToCcidContextPair).containsKey(uuid);
Assert.assertEquals(ccid, (long) uuidToCcidContextPair.get(uuid).first);
Assert.assertEquals(context, (long) uuidToCcidContextPair.get(uuid).second);
@@ -78,11 +80,11 @@ public class ContentControlIdKeeperTest {
public void testCcidRelease(ParcelUuid uuid, int ccid, int expectedListSize) {
Map<ParcelUuid, Pair<Integer, Integer>> uuidToCcidContextPair =
ContentControlIdKeeper.getUuidToCcidContextPairMap();
- Assert.assertTrue(uuidToCcidContextPair.containsKey(uuid));
+ assertThat(uuidToCcidContextPair).containsKey(uuid);
ContentControlIdKeeper.releaseCcid(ccid);
uuidToCcidContextPair = ContentControlIdKeeper.getUuidToCcidContextPairMap();
- Assert.assertFalse(uuidToCcidContextPair.containsKey(uuid));
+ assertThat(uuidToCcidContextPair).doesNotContainKey(uuid);
verify(mLeAudioServiceMock).setCcidInformation(eq(uuid), eq(ccid), eq(0));
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 e60ddac592..182569dda7 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
@@ -21,6 +21,8 @@ import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
import static com.android.bluetooth.bass_client.BassConstants.INVALID_BROADCAST_ID;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.annotation.Nullable;
@@ -229,7 +231,7 @@ public class LeAudioBroadcastServiceTest {
private void stopService() throws TimeoutException {
mService.stop();
mService = LeAudioService.getLeAudioService();
- Assert.assertNull(mService);
+ assertThat(mService).isNull();
}
/** Test getting LeAudio Service */
@@ -749,7 +751,7 @@ public class LeAudioBroadcastServiceTest {
TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
List<BluetoothLeBroadcastMetadata> meta_list = mService.getAllBroadcastMetadata();
- Assert.assertNotNull(meta_list);
+ assertThat(meta_list).isNotNull();
Assert.assertNotEquals(meta_list.size(), 0);
Assert.assertEquals(meta_list.get(0), state_event.broadcastMetadata);
}
@@ -780,7 +782,7 @@ public class LeAudioBroadcastServiceTest {
mService.messageFromNative(state_event);
// Verify if broadcast is active
- Assert.assertTrue(mService.isBroadcastActive());
+ assertThat(mService.isBroadcastActive()).isTrue();
mService.stopBroadcast(broadcastId);
verify(mLeAudioBroadcasterNativeInterface).stopBroadcast(eq(broadcastId));
@@ -797,13 +799,13 @@ public class LeAudioBroadcastServiceTest {
mService.messageFromNative(state_event);
// Verify if broadcast is not active
- Assert.assertFalse(mService.isBroadcastActive());
+ assertThat(mService.isBroadcastActive()).isFalse();
}
private void verifyConnectionStateIntent(
int timeoutMs, BluetoothDevice device, int newState, int prevState) {
Intent intent = TestUtils.waitForIntent(timeoutMs, mIntentQueue);
- Assert.assertNotNull(intent);
+ assertThat(intent).isNotNull();
Assert.assertEquals(
BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED, intent.getAction());
Assert.assertEquals(
@@ -825,7 +827,7 @@ public class LeAudioBroadcastServiceTest {
LeAudioStackEvent stackEvent =
new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED);
mService.messageFromNative(stackEvent);
- Assert.assertTrue(mService.mLeAudioNativeIsInitialized);
+ assertThat(mService.mLeAudioNativeIsInitialized).isTrue();
}
private void prepareConnectedUnicastDevice(int groupId, BluetoothDevice device) {
@@ -844,7 +846,7 @@ public class LeAudioBroadcastServiceTest {
doReturn(new ParcelUuid[] {BluetoothUuid.LE_AUDIO})
.when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- Assert.assertTrue(mService.connect(device));
+ assertThat(mService.connect(device)).isTrue();
// Verify the connection state broadcast, and that we are in Connected state
verifyConnectionStateIntent(
@@ -1108,7 +1110,7 @@ public class LeAudioBroadcastServiceTest {
/* Imitate setting device in call */
mService.setInCall(true);
- Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isTrue();
/* Check if broadcast is paused by InCall handling */
verify(mLeAudioBroadcasterNativeInterface).pauseBroadcast(eq(broadcastId));
@@ -1158,7 +1160,7 @@ public class LeAudioBroadcastServiceTest {
eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class));
/* Verify if broadcast triggers transition */
- Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isFalse();
}
@Test
@@ -1174,7 +1176,7 @@ public class LeAudioBroadcastServiceTest {
/* Imitate setting device in call */
mService.handleAudioModeChange(AudioManager.MODE_IN_CALL);
- Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isTrue();
/* Check if broadcast is paused by AudioMode handling */
verify(mLeAudioBroadcasterNativeInterface).pauseBroadcast(eq(broadcastId));
@@ -1233,7 +1235,7 @@ public class LeAudioBroadcastServiceTest {
if (Flags.leaudioBigDependsOnAudioState()) {
/* Verify if broadcast triggers transition */
- Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isFalse();
}
/* Verify if broadcast is auto-started on start */
@@ -1257,7 +1259,7 @@ public class LeAudioBroadcastServiceTest {
create_event.valueInt2 = LeAudioStackEvent.STATUS_LOCAL_STREAM_REQUESTED;
mService.messageFromNative(create_event);
- Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isTrue();
/* Check if broadcast is paused triggered by group change request */
verify(mLeAudioBroadcasterNativeInterface).pauseBroadcast(eq(broadcastId));
@@ -1309,7 +1311,7 @@ public class LeAudioBroadcastServiceTest {
if (Flags.leaudioBigDependsOnAudioState()) {
/* Verify if broadcast triggers transition */
- Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isFalse();
}
verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId));
@@ -1335,7 +1337,7 @@ public class LeAudioBroadcastServiceTest {
/* Imitate setting device in call */
mService.setInCall(true);
- Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isTrue();
/* Broadcast already paused, not call pause again by InCall handling */
verify(mLeAudioBroadcasterNativeInterface, never()).pauseBroadcast(eq(broadcastId));
@@ -1379,7 +1381,7 @@ public class LeAudioBroadcastServiceTest {
eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class));
/* Verify if broadcast triggers transition */
- Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isFalse();
}
@Test
@@ -1402,7 +1404,7 @@ public class LeAudioBroadcastServiceTest {
/* Imitate setting device in call */
mService.handleAudioModeChange(AudioManager.MODE_IN_CALL);
- Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isTrue();
/* Broadcast already paused, not call pause again by AudioMode handling */
verify(mLeAudioBroadcasterNativeInterface, never()).pauseBroadcast(eq(broadcastId));
@@ -1454,7 +1456,7 @@ public class LeAudioBroadcastServiceTest {
eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class));
/* Verify if broadcast triggers transition */
- Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isFalse();
}
@Test
@@ -1480,7 +1482,7 @@ public class LeAudioBroadcastServiceTest {
create_event.valueInt2 = LeAudioStackEvent.STATUS_LOCAL_STREAM_REQUESTED;
mService.messageFromNative(create_event);
- Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isTrue();
/* Broadcast already paused, not call pause again by group change request */
verify(mLeAudioBroadcasterNativeInterface, never()).pauseBroadcast(eq(broadcastId));
@@ -1524,7 +1526,7 @@ public class LeAudioBroadcastServiceTest {
.handleBluetoothActiveDeviceChanged(
eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class));
/* Verify if broadcast triggers transition */
- Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent());
+ assertThat(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()).isFalse();
}
@Test
@@ -1577,7 +1579,7 @@ public class LeAudioBroadcastServiceTest {
ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor =
ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class);
- Assert.assertTrue(mService.setActiveDevice(mDevice2));
+ assertThat(mService.setActiveDevice(mDevice2)).isTrue();
verify(mAudioManager)
.handleBluetoothActiveDeviceChanged(
@@ -1585,7 +1587,7 @@ public class LeAudioBroadcastServiceTest {
List<BluetoothProfileConnectionInfo> connInfos =
connectionInfoArgumentCaptor.getAllValues();
Assert.assertEquals(connInfos.size(), 1);
- Assert.assertFalse(connInfos.get(0).isLeOutput());
+ assertThat(connInfos.get(0).isLeOutput()).isFalse();
Assert.assertEquals(mService.mUnicastGroupIdDeactivatedForBroadcastTransition, groupId2);
}
@@ -1633,7 +1635,7 @@ public class LeAudioBroadcastServiceTest {
TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
Assert.assertEquals(groupId1, mService.mUnicastGroupIdDeactivatedForBroadcastTransition);
- Assert.assertTrue(onBroadcastToUnicastFallbackGroupChangedCallbackCalled);
+ assertThat(onBroadcastToUnicastFallbackGroupChangedCallbackCalled).isTrue();
onBroadcastToUnicastFallbackGroupChangedCallbackCalled = false;
synchronized (mService.mLeAudioCallbacks) {
@@ -1691,7 +1693,7 @@ public class LeAudioBroadcastServiceTest {
List<BluetoothProfileConnectionInfo> connInfos =
connectionInfoArgumentCaptor.getAllValues();
Assert.assertEquals(connInfos.size(), 1);
- Assert.assertFalse(connInfos.get(0).isLeOutput());
+ assertThat(connInfos.get(0).isLeOutput()).isFalse();
Assert.assertEquals(mService.getBroadcastToUnicastFallbackGroup(), groupId2);
}
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 1ffcef09f0..988042721b 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
@@ -607,8 +607,7 @@ public class LeAudioServiceTest {
if (expectedIntent) {
verifyActiveDeviceStateIntent(AUDIO_MANAGER_DEVICE_ADD_TIMEOUT_MS, device);
} else {
- Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(device));
- assertThat(intent).isNull();
+ TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(device));
}
}
@@ -622,8 +621,7 @@ public class LeAudioServiceTest {
if (expectedIntent) {
verifyActiveDeviceStateIntent(AUDIO_MANAGER_DEVICE_ADD_TIMEOUT_MS, null);
} else {
- Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(device));
- assertThat(intent).isNull();
+ TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(device));
}
}
@@ -1073,8 +1071,7 @@ public class LeAudioServiceTest {
}
private void verifyNoConnectionStateIntent(int timeoutMs, BluetoothDevice device) {
- Intent intent = TestUtils.waitForNoIntent(timeoutMs, mDeviceQueueMap.get(device));
- assertThat(intent).isNull();
+ TestUtils.waitForNoIntent(timeoutMs, mDeviceQueueMap.get(device));
}
/** Test setting connection policy */
@@ -1936,12 +1933,12 @@ public class LeAudioServiceTest {
3);
injectGroupStatusChange(testGroupId, BluetoothLeAudio.GROUP_STATUS_ACTIVE);
- /* Expect 2 calles to Audio Manager - one for output and second for input as this is
+ /* Expect 2 calls to Audio Manager - one for output and second for input as this is
* Conversational use case */
verify(mAudioManager, times(2))
.handleBluetoothActiveDeviceChanged(
any(), any(), any(BluetoothProfileConnectionInfo.class));
- /* Since LeAudioService called AudioManager - assume Audio manager calles properly callback
+ /* Since LeAudioService called AudioManager - assume Audio manager calls properly callback
* mAudioManager.onAudioDeviceAdded
*/
injectAudioDeviceAdded(mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true);
@@ -1957,8 +1954,7 @@ public class LeAudioServiceTest {
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL;
injectAudioConfChanged(testGroupId, contexts, 3);
- Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
- assertThat(intent).isNull();
+ TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
}
/** Test native interface audio configuration changed message handling */
@@ -1968,8 +1964,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
injectAudioConfChanged(testGroupId, 0, 3);
- Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
- assertThat(intent).isNull();
+ TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
}
/**
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/AppScanStatsTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/AppScanStatsTest.java
index de23afb6fb..24d8e2c0b5 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/AppScanStatsTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/AppScanStatsTest.java
@@ -16,7 +16,7 @@
package com.android.bluetooth.le_scan;
-import static com.android.bluetooth.Utils.sSystemClock;
+import static com.android.bluetooth.Utils.getSystemClock;
import static com.google.common.truth.Truth.assertThat;
@@ -78,7 +78,8 @@ public class AppScanStatsTest {
WorkSource source = null;
AppScanStats appScanStats =
- new AppScanStats(name, source, map, mAdapterService, mMockScanHelper, sSystemClock);
+ new AppScanStats(
+ name, source, map, mAdapterService, mMockScanHelper, getSystemClock());
assertThat(appScanStats.mScannerMap).isEqualTo(map);
assertThat(appScanStats.mScanHelper).isEqualTo(mMockScanHelper);
@@ -92,7 +93,8 @@ public class AppScanStatsTest {
WorkSource source = null;
AppScanStats appScanStats =
- new AppScanStats(name, source, map, mAdapterService, mMockScanHelper, sSystemClock);
+ new AppScanStats(
+ name, source, map, mAdapterService, mMockScanHelper, getSystemClock());
ScanSettings settings = new ScanSettings.Builder().build();
List<ScanFilter> filters = new ArrayList<>();
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternListTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternListTest.java
new file mode 100644
index 0000000000..62c8545fa2
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/MsftAdvMonitorMergedPatternListTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.le_scan;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.le.ScanFilter;
+import android.os.ParcelUuid;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.UUID;
+
+/** Test cases for {@link MsftAdvMonitorMergedPatternList}. */
+@RunWith(JUnit4.class)
+public final class MsftAdvMonitorMergedPatternListTest {
+ private static final ParcelUuid SERVICE_DATA_UUID =
+ new ParcelUuid(UUID.fromString("01234567-890A-BCDE-F123-4567890ABCDE"));
+ private static final byte[] SERVICE_DATA = new byte[] {0x01, 0x02, 0x03};
+
+ private static final ParcelUuid ANOTHER_SERVICE_DATA_UUID =
+ new ParcelUuid(UUID.fromString("12345678-90AB-CDEF-1234-567890ABCDEF"));
+
+ @Test
+ public void testAddandRemove() {
+ MsftAdvMonitorMergedPatternList patternList = new MsftAdvMonitorMergedPatternList();
+ int filterIndex = 0;
+ int addedFilterIndex = filterIndex;
+
+ // Ensure returned filter index is the same as passed filter index
+ MsftAdvMonitor monitor =
+ new MsftAdvMonitor(
+ new ScanFilter.Builder()
+ .setServiceData(SERVICE_DATA_UUID, SERVICE_DATA)
+ .build());
+ assertThat(patternList.add(filterIndex, monitor.getPatterns())).isEqualTo(filterIndex);
+
+ // Add a different pattern and ensure returned filter index is the same as passed filter
+ // index
+ filterIndex++;
+ MsftAdvMonitor anotherMonitor =
+ new MsftAdvMonitor(
+ new ScanFilter.Builder()
+ .setServiceData(ANOTHER_SERVICE_DATA_UUID, SERVICE_DATA)
+ .build());
+ assertThat(patternList.add(filterIndex, anotherMonitor.getPatterns()))
+ .isEqualTo(filterIndex);
+
+ // Add the same first pattern with different filter index and confirm previous filter index
+ // was returned
+ filterIndex++;
+ assertThat(patternList.add(filterIndex, monitor.getPatterns())).isEqualTo(addedFilterIndex);
+
+ // Only removing the last filter index should result in successful removal
+ assertThat(patternList.remove(addedFilterIndex)).isEqualTo(false);
+ assertThat(patternList.remove(addedFilterIndex)).isEqualTo(true);
+ }
+}
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 041aea999b..e0f908d70b 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
@@ -19,6 +19,8 @@ package com.android.bluetooth.le_scan;
import static android.bluetooth.BluetoothDevice.PHY_LE_1M_MASK;
import static android.bluetooth.BluetoothDevice.PHY_LE_CODED;
import static android.bluetooth.BluetoothDevice.PHY_LE_CODED_MASK;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH;
import static android.bluetooth.le.ScanSettings.PHY_LE_ALL_SUPPORTED;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY;
@@ -65,6 +67,7 @@ import android.os.BatteryStatsManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Message;
+import android.os.ParcelUuid;
import android.os.SystemProperties;
import android.os.WorkSource;
import android.os.test.TestLooper;
@@ -106,7 +109,9 @@ import org.mockito.junit.MockitoRule;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.UUID;
/** Test cases for {@link ScanManager}. */
@SmallTest
@@ -138,6 +143,13 @@ public class ScanManagerTest {
// MSFT-based hardware scan offload sysprop
private static final String MSFT_HCI_EXT_ENABLED = "bluetooth.core.le.use_msft_hci_ext";
+ private static final Map<Integer, Integer> defaultScanMode =
+ Map.of(
+ SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER,
+ SCAN_MODE_BALANCED, SCAN_MODE_BALANCED,
+ SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY,
+ SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
+
private final Context mTargetContext = InstrumentationRegistry.getTargetContext();
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
@@ -152,6 +164,7 @@ public class ScanManagerTest {
private long mScanReportDelay;
private FakeTimeProvider mTimeProvider;
private InOrder mInOrder;
+ private int mClientId;
@Before
public void setUp() throws Exception {
@@ -219,6 +232,7 @@ public class ScanManagerTest {
doReturn(mTargetContext.getUser()).when(mAdapterService).getUser();
doReturn(mTargetContext.getPackageName()).when(mAdapterService).getPackageName();
+ mClientId = 0;
mTimeProvider = new FakeTimeProvider();
mLooper = new TestLooper();
mScanManager =
@@ -270,26 +284,38 @@ public class ScanManagerTest {
}
private ScanClient createScanClient(
- int id,
boolean isFiltered,
- boolean isEmptyFilter,
int scanMode,
boolean isBatch,
boolean isAutoBatch,
int appUid,
- AppScanStats appScanStats) {
- List<ScanFilter> scanFilterList = createScanFilterList(isFiltered, isEmptyFilter);
+ AppScanStats appScanStats,
+ List<ScanFilter> scanFilterList) {
ScanSettings scanSettings = createScanSettings(scanMode, isBatch, isAutoBatch);
- ScanClient client = new ScanClient(id, scanSettings, scanFilterList, appUid);
+ mClientId = mClientId + 1;
+ ScanClient client = new ScanClient(mClientId, scanSettings, scanFilterList, appUid);
client.stats = appScanStats;
- client.stats.recordScanStart(scanSettings, scanFilterList, isFiltered, false, id, null);
+ client.stats.recordScanStart(
+ scanSettings, scanFilterList, isFiltered, false, mClientId, null);
return client;
}
- private ScanClient createScanClient(int id, boolean isFiltered, int scanMode) {
+ private ScanClient createScanClient(
+ boolean isFiltered,
+ boolean isEmptyFilter,
+ int scanMode,
+ boolean isBatch,
+ boolean isAutoBatch,
+ int appUid,
+ AppScanStats appScanStats) {
+ List<ScanFilter> scanFilterList = createScanFilterList(isFiltered, isEmptyFilter);
+ return createScanClient(
+ isFiltered, scanMode, isBatch, isAutoBatch, appUid, appScanStats, scanFilterList);
+ }
+
+ private ScanClient createScanClient(boolean isFiltered, int scanMode) {
return createScanClient(
- id,
isFiltered,
false,
scanMode,
@@ -300,15 +326,13 @@ public class ScanManagerTest {
}
private ScanClient createScanClient(
- int id, boolean isFiltered, int scanMode, int appUid, AppScanStats appScanStats) {
- return createScanClient(
- id, isFiltered, false, scanMode, false, false, appUid, appScanStats);
+ boolean isFiltered, int scanMode, int appUid, AppScanStats appScanStats) {
+ return createScanClient(isFiltered, false, scanMode, false, false, appUid, appScanStats);
}
private ScanClient createScanClient(
- int id, boolean isFiltered, int scanMode, boolean isBatch, boolean isAutoBatch) {
+ boolean isFiltered, int scanMode, boolean isBatch, boolean isAutoBatch) {
return createScanClient(
- id,
isFiltered,
false,
scanMode,
@@ -318,10 +342,8 @@ public class ScanManagerTest {
mMockAppScanStats);
}
- private ScanClient createScanClient(
- int id, boolean isFiltered, boolean isEmptyFilter, int scanMode) {
+ private ScanClient createScanClient(boolean isFiltered, boolean isEmptyFilter, int scanMode) {
return createScanClient(
- id,
isFiltered,
isEmptyFilter,
scanMode,
@@ -433,33 +455,22 @@ public class ScanManagerTest {
public void testScreenOffStartUnfilteredScan() {
// Set filtered scan flag
final boolean isFiltered = false;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
@@ -476,17 +487,12 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -500,99 +506,66 @@ public class ScanManagerTest {
// Set filtered scan flag
final boolean isFiltered = true;
final boolean isEmptyFilter = true;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, isEmptyFilter, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, isEmptyFilter, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
public void testScreenOnStartUnfilteredScan() {
// Set filtered scan flag
final boolean isFiltered = false;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
public void testScreenOnStartFilteredScan() {
// Set filtered scan flag
final boolean isFiltered = true;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
-
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
@@ -609,17 +582,12 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
@@ -647,17 +615,12 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -675,99 +638,80 @@ public class ScanManagerTest {
public void testUnfilteredScanTimeout() {
// Set filtered scan flag
final boolean isFiltered = false;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_OPPORTUNISTIC);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_OPPORTUNISTIC);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_OPPORTUNISTIC);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_OPPORTUNISTIC);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- // Wait for scan timeout
- advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS);
- mLooper.dispatchAll();
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- assertThat(client.stats.isScanTimeout(client.scannerId)).isTrue();
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Set as background app
- sendMessageWaitForProcessed(createImportanceMessage(false));
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Set as foreground app
- sendMessageWaitForProcessed(createImportanceMessage(true));
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_OPPORTUNISTIC;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ // Wait for scan timeout
+ advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS);
+ mLooper.dispatchAll();
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ assertThat(client.stats.isScanTimeout(client.scannerId)).isTrue();
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Set as background app
+ sendMessageWaitForProcessed(createImportanceMessage(false));
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Set as foreground app
+ sendMessageWaitForProcessed(createImportanceMessage(true));
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
public void testFilteredScanTimeout() {
// Set filtered scan flag
final boolean isFiltered = true;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_POWER);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan, this sends scan timeout message with delay
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- // Move time forward so scan timeout message can be dispatched
- advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS);
- // Since we are using a TestLooper, need to mock AppScanStats.isScanningTooLong to
- // return true because no real time is elapsed
- doReturn(true).when(mMockAppScanStats).isScanningTooLong();
- syncHandler(ScanManager.MSG_SCAN_TIMEOUT);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- assertThat(client.stats.isScanTimeout(client.scannerId)).isTrue();
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- assertThat(client.settings.getScanMode()).isEqualTo(SCAN_MODE_SCREEN_OFF);
- // Set as background app
- sendMessageWaitForProcessed(createImportanceMessage(false));
- assertThat(client.settings.getScanMode()).isEqualTo(SCAN_MODE_SCREEN_OFF);
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Set as foreground app
- sendMessageWaitForProcessed(createImportanceMessage(true));
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_LOW_POWER;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan, this sends scan timeout message with delay
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ // Move time forward so scan timeout message can be dispatched
+ advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS);
+ // Since we are using a TestLooper, need to mock AppScanStats.isScanningTooLong
+ // to
+ // return true because no real time is elapsed
+ doReturn(true).when(mMockAppScanStats).isScanningTooLong();
+ syncHandler(ScanManager.MSG_SCAN_TIMEOUT);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ assertThat(client.stats.isScanTimeout(client.scannerId)).isTrue();
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ assertThat(client.settings.getScanMode()).isEqualTo(SCAN_MODE_SCREEN_OFF);
+ // Set as background app
+ sendMessageWaitForProcessed(createImportanceMessage(false));
+ assertThat(client.settings.getScanMode()).isEqualTo(SCAN_MODE_SCREEN_OFF);
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Set as foreground app
+ sendMessageWaitForProcessed(createImportanceMessage(true));
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
@@ -777,7 +721,7 @@ public class ScanManagerTest {
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
// Create scan client
- ScanClient client = createScanClient(0, isFiltered, SCAN_MODE_LOW_POWER);
+ ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
// Put a timeout message in the queue to emulate the scan being started already
Message timeoutMessage =
@@ -802,86 +746,66 @@ public class ScanManagerTest {
public void testSwitchForeBackgroundUnfilteredScan() {
// Set filtered scan flag
final boolean isFiltered = false;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_POWER);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- // Set as background app
- sendMessageWaitForProcessed(createImportanceMessage(false));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Set as foreground app
- sendMessageWaitForProcessed(createImportanceMessage(true));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_LOW_POWER;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ // Set as background app
+ sendMessageWaitForProcessed(createImportanceMessage(false));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Set as foreground app
+ sendMessageWaitForProcessed(createImportanceMessage(true));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ });
}
@Test
public void testSwitchForeBackgroundFilteredScan() {
// Set filtered scan flag
final boolean isFiltered = true;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_POWER);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- // Set as background app
- sendMessageWaitForProcessed(createImportanceMessage(false));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Set as foreground app
- sendMessageWaitForProcessed(createImportanceMessage(true));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_LOW_POWER;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ // Set as background app
+ sendMessageWaitForProcessed(createImportanceMessage(false));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Set as foreground app
+ sendMessageWaitForProcessed(createImportanceMessage(true));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ });
}
@Test
@@ -901,19 +825,14 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
// Set as foreground app
sendMessageWaitForProcessed(createImportanceMessage(true));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -928,14 +847,6 @@ public class ScanManagerTest {
@Test
public void testUpDowngradeStartScanForConcurrency() {
- // Set filtered scan flag
- final boolean isFiltered = true;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_BALANCED);
doReturn(DEFAULT_SCAN_UPGRADE_DURATION_MILLIS)
.when(mAdapterService)
.getScanUpgradeDurationMillis();
@@ -943,39 +854,38 @@ public class ScanManagerTest {
.when(mAdapterService)
.getScanDowngradeDurationMillis();
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ // Set filtered scan flag
+ final boolean isFiltered = true;
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Set as foreground app
- sendMessageWaitForProcessed(createImportanceMessage(true));
- // Set connecting state
- sendMessageWaitForProcessed(createConnectingMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- // Wait for upgrade and downgrade duration
- int max_duration =
- DEFAULT_SCAN_UPGRADE_DURATION_MILLIS
- > DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS
- ? DEFAULT_SCAN_UPGRADE_DURATION_MILLIS
- : DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS;
- advanceTime(max_duration);
- mLooper.dispatchAll();
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_BALANCED;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Set as foreground app
+ sendMessageWaitForProcessed(createImportanceMessage(true));
+ // Set connecting state
+ sendMessageWaitForProcessed(createConnectingMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ // Wait for upgrade and downgrade duration
+ int max_duration =
+ DEFAULT_SCAN_UPGRADE_DURATION_MILLIS
+ > DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS
+ ? DEFAULT_SCAN_UPGRADE_DURATION_MILLIS
+ : DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS;
+ advanceTime(max_duration);
+ mLooper.dispatchAll();
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ });
}
@Test
@@ -996,19 +906,14 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
// Set as foreground app
sendMessageWaitForProcessed(createImportanceMessage(true));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -1042,19 +947,14 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
// Set as foreground app
sendMessageWaitForProcessed(createImportanceMessage(true));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -1076,51 +976,41 @@ public class ScanManagerTest {
@Test
public void testDowngradeDuringScanForConcurrencyBackground() {
- // Set filtered scan flag
- final boolean isFiltered = true;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_POWER);
-
doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
.when(mAdapterService)
.getScanDowngradeDurationMillis();
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ // Set filtered scan flag
+ final boolean isFiltered = true;
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Set as foreground app
- sendMessageWaitForProcessed(createImportanceMessage(true));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- // Set connecting state
- sendMessageWaitForProcessed(createConnectingMessage(true));
- // Set as background app
- sendMessageWaitForProcessed(createImportanceMessage(false));
- // Wait for downgrade duration
- advanceTime(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS);
- mLooper.dispatchAll();
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_LOW_POWER;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Set as foreground app
+ sendMessageWaitForProcessed(createImportanceMessage(true));
+ // Create scan client
+ ScanClient client = createScanClient(isFiltered, scanMode);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ // Set connecting state
+ sendMessageWaitForProcessed(createConnectingMessage(true));
+ // Set as background app
+ sendMessageWaitForProcessed(createImportanceMessage(false));
+ // Wait for downgrade duration
+ advanceTime(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS);
+ mLooper.dispatchAll();
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(expectedScanMode);
+ });
}
@Test
@@ -1139,17 +1029,12 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode, isBatch, isAutoBatch);
+ ScanClient client = createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
@@ -1180,17 +1065,12 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeMap.size(); i++) {
int scanMode = scanModeMap.keyAt(i);
int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode, isBatch, isAutoBatch);
+ ScanClient client = createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
@@ -1213,47 +1093,38 @@ public class ScanManagerTest {
final boolean isAutoBatch = true;
// Set report delay for auto batch scan callback type
mScanReportDelay = ScanSettings.AUTO_BATCH_MIN_REPORT_DELAY_MILLIS;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_SCREEN_OFF);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_SCREEN_OFF);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_SCREEN_OFF);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_SCREEN_OFF);
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
-
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode, isBatch, isAutoBatch);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanParams()).isNull();
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanParams()).isNull();
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanParams()).isNull();
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_SCREEN_OFF;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ // Create scan client
+ ScanClient client =
+ createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
+ assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanParams()).isNull();
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanParams()).isNull();
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
+ assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanParams()).isNull();
+ });
}
@Test
@@ -1264,47 +1135,40 @@ public class ScanManagerTest {
final boolean isAutoBatch = true;
// Set report delay for auto batch scan callback type
mScanReportDelay = ScanSettings.AUTO_BATCH_MIN_REPORT_DELAY_MILLIS;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_SCREEN_OFF);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_SCREEN_OFF);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_SCREEN_OFF);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_SCREEN_OFF);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- // Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode, isBatch, isAutoBatch);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanParams().scanMode).isEqualTo(expectedScanMode);
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- assertThat(mScanManager.getRegularScanQueue()).contains(client);
- assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanParams()).isNull();
- // Turn off screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(false));
- assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanParams().scanMode).isEqualTo(expectedScanMode);
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ expectedScanMode = SCAN_MODE_SCREEN_OFF;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ // Create scan client
+ ScanClient client =
+ createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanQueue()).contains(client);
+ assertThat(mScanManager.getBatchScanParams().scanMode)
+ .isEqualTo(expectedScanMode);
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ assertThat(mScanManager.getRegularScanQueue()).contains(client);
+ assertThat(client.settings.getScanMode()).isEqualTo(scanMode);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanParams()).isNull();
+ // Turn off screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(false));
+ assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
+ assertThat(mScanManager.getBatchScanQueue()).contains(client);
+ assertThat(mScanManager.getBatchScanParams().scanMode)
+ .isEqualTo(expectedScanMode);
+ });
}
@Test
@@ -1321,11 +1185,11 @@ public class ScanManagerTest {
for (int i = 0; i < scanModeArr.length; i++) {
int scanMode = scanModeArr[i];
- Log.d(TAG, "ScanMode: " + String.valueOf(scanMode));
+ Log.d(TAG, "ScanMode: " + scanMode);
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -1396,7 +1260,7 @@ public class ScanManagerTest {
mScanHelper,
mTimeProvider));
// Create scan client for the app, which also records scan start
- ScanClient client = createScanClient(i, isFiltered, scanMode, UID, appScanStats);
+ ScanClient client = createScanClient(isFiltered, scanMode, UID, appScanStats);
// Verify that the app scan start is logged
mInOrder.verify(mMetricsLogger)
.logAppScanStateChanged(
@@ -1418,7 +1282,7 @@ public class ScanManagerTest {
advanceTime(scanTestDuration);
// Record scan stop
- client.stats.recordScanStop(i);
+ client.stats.recordScanStop(mClientId);
// Verify that the app scan stop is logged
mInOrder.verify(mMetricsLogger)
.logAppScanStateChanged(
@@ -1468,7 +1332,7 @@ public class ScanManagerTest {
mTimeProvider));
// Create scan client for the first app
ScanClient client1 =
- createScanClient(0, isFiltered, SCAN_MODE_LOW_POWER, UID_1, appScanStats1);
+ createScanClient(isFiltered, SCAN_MODE_LOW_POWER, UID_1, appScanStats1);
// Start scan with lower duty cycle for the first app
sendMessageWaitForProcessed(createStartStopScanMessage(true, client1));
advanceTime(scanTestDuration);
@@ -1489,8 +1353,7 @@ public class ScanManagerTest {
mScanHelper,
mTimeProvider));
// Create scan client for the second app
- ScanClient client2 =
- createScanClient(1, isFiltered, SCAN_MODE_BALANCED, UID_2, appScanStats2);
+ ScanClient client2 = createScanClient(isFiltered, SCAN_MODE_BALANCED, UID_2, appScanStats2);
// Start scan with higher duty cycle for the second app
sendMessageWaitForProcessed(createStartStopScanMessage(true, client2));
// Verify radio scan stop is logged with the first app
@@ -1527,7 +1390,7 @@ public class ScanManagerTest {
mTimeProvider));
// Create scan client for the third app
ScanClient client3 =
- createScanClient(2, isFiltered, SCAN_MODE_LOW_LATENCY, UID_3, appScanStats3);
+ createScanClient(isFiltered, SCAN_MODE_LOW_LATENCY, UID_3, appScanStats3);
// Start scan with highest duty cycle for the third app
sendMessageWaitForProcessed(createStartStopScanMessage(true, client3));
// Verify radio scan stop is logged with the second app
@@ -1564,7 +1427,7 @@ public class ScanManagerTest {
mTimeProvider));
// Create scan client for the fourth app
ScanClient client4 =
- createScanClient(3, isFiltered, SCAN_MODE_AMBIENT_DISCOVERY, UID_4, appScanStats4);
+ createScanClient(isFiltered, SCAN_MODE_AMBIENT_DISCOVERY, UID_4, appScanStats4);
// Start scan with lower duty cycle for the fourth app
sendMessageWaitForProcessed(createStartStopScanMessage(true, client4));
// Verify radio scan stop is not logged with the third app since there is no change in radio
@@ -1714,7 +1577,7 @@ public class ScanManagerTest {
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
Mockito.clearInvocations(mMetricsLogger);
// Create scan client
- ScanClient client = createScanClient(0, isFiltered, SCAN_MODE_LOW_POWER);
+ ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
mInOrder.verify(mMetricsLogger, never())
@@ -1750,7 +1613,7 @@ public class ScanManagerTest {
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
Mockito.clearInvocations(mMetricsLogger);
// Create scan client
- ScanClient client = createScanClient(0, isFiltered, SCAN_MODE_LOW_POWER);
+ ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
mInOrder.verify(mMetricsLogger, never())
@@ -1812,8 +1675,8 @@ public class ScanManagerTest {
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
Mockito.clearInvocations(mMetricsLogger);
// Create scan clients with different duty cycles
- ScanClient client = createScanClient(0, isFiltered, SCAN_MODE_LOW_POWER);
- ScanClient client2 = createScanClient(1, isFiltered, SCAN_MODE_BALANCED);
+ ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
+ ScanClient client2 = createScanClient(isFiltered, SCAN_MODE_BALANCED);
// Start scan with lower duty cycle
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
mInOrder.verify(mMetricsLogger, never())
@@ -1876,15 +1739,10 @@ public class ScanManagerTest {
int scanMode = scanModeMap.keyAt(i);
long weightedScanDuration =
(long) (scanTestDuration * scanModeMap.get(scanMode) * 0.01);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " weightedScanDuration: "
- + String.valueOf(weightedScanDuration));
+ Log.d(TAG, "ScanMode: " + scanMode + " weightedScanDuration: " + weightedScanDuration);
// Create scan client
- ScanClient client = createScanClient(i, isFiltered, scanMode);
+ ScanClient client = createScanClient(isFiltered, scanMode);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
// Wait for scan test duration
@@ -1929,7 +1787,7 @@ public class ScanManagerTest {
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(0, isFiltered, SCAN_MODE_LOW_LATENCY);
+ ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_LATENCY);
// Start Scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -1953,7 +1811,7 @@ public class ScanManagerTest {
// Turn off screen
sendMessageWaitForProcessed(createScreenOnOffMessage(false));
// Create scan client
- ScanClient client = createScanClient(0, isFiltered, SCAN_MODE_LOW_LATENCY);
+ ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_LATENCY);
// Start Scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).contains(client);
@@ -1975,9 +1833,7 @@ public class ScanManagerTest {
assertThat(mScanManager.mIsConnecting).isFalse();
mScanManager.handleBluetoothProfileConnectionStateChanged(
- BluetoothProfile.A2DP,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.A2DP, STATE_DISCONNECTED, STATE_CONNECTING);
mLooper.dispatchAll();
assertThat(mScanManager.mIsConnecting).isTrue();
@@ -1991,88 +1847,47 @@ public class ScanManagerTest {
assertThat(mScanManager.mIsConnecting).isFalse();
mScanManager.handleBluetoothProfileConnectionStateChanged(
- BluetoothProfile.HEADSET,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.HEADSET, STATE_DISCONNECTED, STATE_CONNECTING);
mScanManager.handleBluetoothProfileConnectionStateChanged(
- BluetoothProfile.A2DP,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.A2DP, STATE_DISCONNECTED, STATE_CONNECTING);
mScanManager.handleBluetoothProfileConnectionStateChanged(
- BluetoothProfile.HID_HOST,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.HID_HOST, STATE_DISCONNECTED, STATE_CONNECTING);
mLooper.dispatchAll();
assertThat(mScanManager.mProfilesConnecting).isEqualTo(3);
}
- @Test
- public void testSetScanPhy() {
+ private void phytest(int phy, int expectedPhy) {
final boolean isFiltered = false;
final boolean isEmptyFilter = false;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int phy = PHY_LE_CODED;
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- Log.d(
- TAG,
- "ScanMode: "
- + String.valueOf(scanMode)
- + " expectedScanMode: "
- + String.valueOf(expectedScanMode));
-
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client =
- createScanClientWithPhy(i, isFiltered, isEmptyFilter, scanMode, phy);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- assertThat(client.settings.getPhy()).isEqualTo(phy);
- verify(mScanNativeInterface, atLeastOnce())
- .gattSetScanParameters(anyInt(), anyInt(), anyInt(), eq(PHY_LE_CODED_MASK));
- }
+ defaultScanMode.forEach(
+ (scanMode, expectedScanMode) -> {
+ mClientId = mClientId + 1;
+ Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
+
+ // Turn on screen
+ sendMessageWaitForProcessed(createScreenOnOffMessage(true));
+ // Create scan client
+ ScanClient client =
+ createScanClientWithPhy(
+ mClientId, isFiltered, isEmptyFilter, scanMode, phy);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+
+ assertThat(client.settings.getPhy()).isEqualTo(phy);
+ verify(mScanNativeInterface, atLeastOnce())
+ .gattSetScanParameters(anyInt(), anyInt(), anyInt(), eq(expectedPhy));
+ });
}
@Test
- public void testSetScanPhyAllSupported() {
- final boolean isFiltered = false;
- final boolean isEmptyFilter = false;
- // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
- SparseIntArray scanModeMap = new SparseIntArray();
- scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
- scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
- scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
- scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
-
- for (int i = 0; i < scanModeMap.size(); i++) {
- int phy = PHY_LE_ALL_SUPPORTED;
- int scanMode = scanModeMap.keyAt(i);
- int expectedScanMode = scanModeMap.get(scanMode);
- int expectedPhy = PHY_LE_1M_MASK;
-
- Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
-
- // Turn on screen
- sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client =
- createScanClientWithPhy(i, isFiltered, isEmptyFilter, scanMode, phy);
- // Start scan
- sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
+ public void startScan_whenPhyCoded_isStarted() {
+ phytest(PHY_LE_CODED, PHY_LE_CODED_MASK);
+ }
- assertThat(client.settings.getPhy()).isEqualTo(phy);
- verify(mScanNativeInterface, atLeastOnce())
- .gattSetScanParameters(anyInt(), anyInt(), anyInt(), eq(expectedPhy));
- }
+ @Test
+ public void startScan_whenPhyAllSupported_isStarted() {
+ phytest(PHY_LE_ALL_SUPPORTED, PHY_LE_1M_MASK);
}
@Test
@@ -2082,7 +1897,9 @@ public class ScanManagerTest {
doReturn(false).when(mBluetoothAdapterProxy).isOffloadedScanFilteringSupported();
final boolean isFiltered = true;
- final boolean isEmptyFilter = false;
+ final ParcelUuid serviceUuid =
+ new ParcelUuid(UUID.fromString("12345678-90AB-CDEF-1234-567890ABCDEF"));
+ final byte[] serviceData = new byte[] {0x01, 0x02, 0x03};
boolean isMsftEnabled = SystemProperties.getBoolean(MSFT_HCI_EXT_ENABLED, false);
SystemProperties.set(MSFT_HCI_EXT_ENABLED, Boolean.toString(true));
@@ -2099,19 +1916,45 @@ public class ScanManagerTest {
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
- // Create scan client
- ScanClient client = createScanClient(0, isFiltered, isEmptyFilter, SCAN_MODE_LOW_POWER);
+ // Create scan client with service data
+ List<ScanFilter> scanFilterList =
+ List.of(
+ new ScanFilter.Builder()
+ .setServiceData(serviceUuid, serviceData)
+ .build());
+ ScanClient client =
+ createScanClient(
+ isFiltered,
+ SCAN_MODE_LOW_POWER,
+ false,
+ false,
+ Binder.getCallingUid(),
+ mMockAppScanStats,
+ scanFilterList);
// Start scan
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
- // Verify MSFT APIs
- verify(mScanNativeInterface, atLeastOnce())
+ // Create another scan client with the same service data
+ ScanClient anotherClient =
+ createScanClient(
+ isFiltered,
+ SCAN_MODE_LOW_POWER,
+ false,
+ false,
+ Binder.getCallingUid(),
+ mMockAppScanStats,
+ scanFilterList);
+ // Start scan
+ sendMessageWaitForProcessed(createStartStopScanMessage(true, anotherClient));
+
+ // Verify MSFT APIs are only called once
+ verify(mScanNativeInterface)
.gattClientMsftAdvMonitorAdd(
any(MsftAdvMonitor.Monitor.class),
any(MsftAdvMonitor.Pattern[].class),
any(MsftAdvMonitor.Address.class),
anyInt());
- verify(mScanNativeInterface, atLeastOnce()).gattClientMsftAdvMonitorEnable(eq(true));
+ verify(mScanNativeInterface).gattClientMsftAdvMonitorEnable(eq(true));
} finally {
SystemProperties.set(MSFT_HCI_EXT_ENABLED, Boolean.toString(isMsftEnabled));
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/TransitionalScanHelperTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/TransitionalScanHelperTest.java
index f032abae08..e3db44b86b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/TransitionalScanHelperTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/TransitionalScanHelperTest.java
@@ -393,7 +393,6 @@ public class TransitionalScanHelperTest {
}
@Test
- @EnableFlags(Flags.FLAG_LE_SCAN_USE_ADDRESS_TYPE)
public void onTrackAdvFoundLost() throws Exception {
int scannerId = 1;
int advPktLen = 1;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapContentObserverTest.java b/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapContentObserverTest.java
index 042666d321..316dd5f621 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapContentObserverTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapContentObserverTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.map;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.*;
@@ -45,7 +47,6 @@ import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.BluetoothMethodProxy;
-import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
import com.android.bluetooth.mapapi.BluetoothMapContract;
import com.android.bluetooth.mapapi.BluetoothMapContract.MessageColumns;
@@ -233,8 +234,8 @@ public class BluetoothMapContentObserverTest {
// Validate that 3 addresses were inserted into the database with 2 being the recipients
Assert.assertEquals(3, mProvider.mContents.size());
- Assert.assertTrue(mProvider.mContents.contains(TEST_NUMBER_ONE));
- Assert.assertTrue(mProvider.mContents.contains(TEST_NUMBER_TWO));
+ assertThat(mProvider.mContents.contains(TEST_NUMBER_ONE)).isTrue();
+ assertThat(mProvider.mContents.contains(TEST_NUMBER_TWO)).isTrue();
}
@Test
@@ -386,9 +387,10 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setMessageStatusRead(
- TEST_HANDLE_ONE, type, TEST_URI_STR, TEST_STATUS_VALUE));
+ assertThat(
+ mObserver.setMessageStatusRead(
+ TEST_HANDLE_ONE, type, TEST_URI_STR, TEST_STATUS_VALUE))
+ .isTrue();
Assert.assertEquals(msg.flagRead, TEST_STATUS_VALUE);
}
@@ -404,9 +406,10 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setMessageStatusRead(
- TEST_HANDLE_ONE, type, TEST_URI_STR, TEST_STATUS_VALUE));
+ assertThat(
+ mObserver.setMessageStatusRead(
+ TEST_HANDLE_ONE, type, TEST_URI_STR, TEST_STATUS_VALUE))
+ .isTrue();
Assert.assertEquals(msg.flagRead, TEST_STATUS_VALUE);
}
@@ -421,9 +424,10 @@ public class BluetoothMapContentObserverTest {
mObserver.mProviderClient = mProviderClient;
when(mProviderClient.update(any(), any(), any(), any())).thenReturn(TEST_PLACEHOLDER_INT);
- Assert.assertTrue(
- mObserver.setMessageStatusRead(
- TEST_HANDLE_ONE, type, TEST_URI_STR, TEST_STATUS_VALUE));
+ assertThat(
+ mObserver.setMessageStatusRead(
+ TEST_HANDLE_ONE, type, TEST_URI_STR, TEST_STATUS_VALUE))
+ .isTrue();
Assert.assertEquals(msg.flagRead, TEST_STATUS_VALUE);
}
@@ -446,7 +450,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(mObserver.deleteMessageMms(TEST_HANDLE_ONE));
+ assertThat(mObserver.deleteMessageMms(TEST_HANDLE_ONE)).isTrue();
Assert.assertEquals(msg.threadId, BluetoothMapContentObserver.DELETED_THREAD_ID);
}
@@ -458,7 +462,7 @@ public class BluetoothMapContentObserverTest {
createMsgWithTypeAndThreadId(Mms.MESSAGE_BOX_ALL, TEST_THREAD_ID);
map.put(TEST_HANDLE_ONE, msg);
mObserver.setMsgListMms(map, true);
- Assert.assertNotNull(mObserver.getMsgListMms().get(TEST_HANDLE_ONE));
+ assertThat(mObserver.getMsgListMms().get(TEST_HANDLE_ONE)).isNotNull();
MatrixCursor cursor = new MatrixCursor(new String[] {Mms.THREAD_ID});
cursor.addRow(new Object[] {BluetoothMapContentObserver.DELETED_THREAD_ID});
@@ -469,9 +473,9 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverDelete(any(), any(), any(), any());
- Assert.assertTrue(mObserver.deleteMessageMms(TEST_HANDLE_ONE));
+ assertThat(mObserver.deleteMessageMms(TEST_HANDLE_ONE)).isTrue();
- Assert.assertNull(mObserver.getMsgListMms().get(TEST_HANDLE_ONE));
+ assertThat(mObserver.getMsgListMms().get(TEST_HANDLE_ONE)).isNull();
}
@Test
@@ -492,7 +496,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(mObserver.deleteMessageSms(TEST_HANDLE_ONE));
+ assertThat(mObserver.deleteMessageSms(TEST_HANDLE_ONE)).isTrue();
Assert.assertEquals(msg.threadId, BluetoothMapContentObserver.DELETED_THREAD_ID);
}
@@ -504,7 +508,7 @@ public class BluetoothMapContentObserverTest {
createMsgWithTypeAndThreadId(Sms.MESSAGE_TYPE_ALL, TEST_THREAD_ID);
map.put(TEST_HANDLE_ONE, msg);
mObserver.setMsgListSms(map, true);
- Assert.assertNotNull(mObserver.getMsgListSms().get(TEST_HANDLE_ONE));
+ assertThat(mObserver.getMsgListSms().get(TEST_HANDLE_ONE)).isNotNull();
MatrixCursor cursor = new MatrixCursor(new String[] {Mms.THREAD_ID});
cursor.addRow(new Object[] {BluetoothMapContentObserver.DELETED_THREAD_ID});
@@ -515,9 +519,9 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverDelete(any(), any(), any(), any());
- Assert.assertTrue(mObserver.deleteMessageSms(TEST_HANDLE_ONE));
+ assertThat(mObserver.deleteMessageSms(TEST_HANDLE_ONE)).isTrue();
- Assert.assertNull(mObserver.getMsgListSms().get(TEST_HANDLE_ONE));
+ assertThat(mObserver.getMsgListSms().get(TEST_HANDLE_ONE)).isNull();
}
@Test
@@ -550,7 +554,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.telephonyGetOrCreateThreadId(any(), any());
- Assert.assertTrue(mObserver.unDeleteMessageMms(TEST_HANDLE_ONE));
+ assertThat(mObserver.unDeleteMessageMms(TEST_HANDLE_ONE)).isTrue();
Assert.assertEquals(msg.threadId, TEST_OLD_THREAD_ID);
Assert.assertEquals(msg.type, Mms.MESSAGE_BOX_INBOX);
@@ -586,7 +590,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.telephonyGetOrCreateThreadId(any(), any());
- Assert.assertTrue(mObserver.unDeleteMessageMms(TEST_HANDLE_ONE));
+ assertThat(mObserver.unDeleteMessageMms(TEST_HANDLE_ONE)).isTrue();
Assert.assertEquals(msg.threadId, TEST_OLD_THREAD_ID);
Assert.assertEquals(msg.type, Mms.MESSAGE_BOX_INBOX);
@@ -615,7 +619,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.telephonyGetOrCreateThreadId(any(), any());
- Assert.assertTrue(mObserver.unDeleteMessageMms(TEST_HANDLE_ONE));
+ assertThat(mObserver.unDeleteMessageMms(TEST_HANDLE_ONE)).isTrue();
// Nothing changes when thread id is not BluetoothMapContentObserver.DELETED_THREAD_ID
Assert.assertEquals(msg.threadId, TEST_THREAD_ID);
@@ -644,7 +648,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.telephonyGetOrCreateThreadId(any(), any());
- Assert.assertTrue(mObserver.unDeleteMessageSms(TEST_HANDLE_ONE));
+ assertThat(mObserver.unDeleteMessageSms(TEST_HANDLE_ONE)).isTrue();
Assert.assertEquals(msg.threadId, TEST_OLD_THREAD_ID);
Assert.assertEquals(msg.type, Sms.MESSAGE_TYPE_INBOX);
@@ -669,7 +673,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.telephonyGetOrCreateThreadId(any(), any());
- Assert.assertTrue(mObserver.unDeleteMessageSms(TEST_HANDLE_ONE));
+ assertThat(mObserver.unDeleteMessageSms(TEST_HANDLE_ONE)).isTrue();
// Nothing changes when thread id is not BluetoothMapContentObserver.DELETED_THREAD_ID
Assert.assertEquals(msg.threadId, TEST_THREAD_ID);
@@ -708,12 +712,13 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setEmailMessageStatusDelete(
- mCurrentFolder,
- TEST_URI_STR,
- TEST_HANDLE_ONE,
- BluetoothMapAppParams.STATUS_VALUE_YES));
+ assertThat(
+ mObserver.setEmailMessageStatusDelete(
+ mCurrentFolder,
+ TEST_URI_STR,
+ TEST_HANDLE_ONE,
+ BluetoothMapAppParams.STATUS_VALUE_YES))
+ .isTrue();
Assert.assertEquals(msg.folderId, TEST_DELETE_FOLDER_ID);
}
@@ -729,12 +734,13 @@ public class BluetoothMapContentObserverTest {
mObserver.setMsgListMsg(map, true);
doReturn(0).when(mMapMethodProxy).contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertFalse(
- mObserver.setEmailMessageStatusDelete(
- mCurrentFolder,
- TEST_URI_STR,
- TEST_HANDLE_ONE,
- BluetoothMapAppParams.STATUS_VALUE_YES));
+ assertThat(
+ mObserver.setEmailMessageStatusDelete(
+ mCurrentFolder,
+ TEST_URI_STR,
+ TEST_HANDLE_ONE,
+ BluetoothMapAppParams.STATUS_VALUE_YES))
+ .isFalse();
}
@Test
@@ -755,12 +761,13 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setEmailMessageStatusDelete(
- mCurrentFolder,
- TEST_URI_STR,
- TEST_HANDLE_ONE,
- BluetoothMapAppParams.STATUS_VALUE_NO));
+ assertThat(
+ mObserver.setEmailMessageStatusDelete(
+ mCurrentFolder,
+ TEST_URI_STR,
+ TEST_HANDLE_ONE,
+ BluetoothMapAppParams.STATUS_VALUE_NO))
+ .isTrue();
Assert.assertEquals(msg.folderId, TEST_INBOX_FOLDER_ID);
}
@@ -783,12 +790,13 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setEmailMessageStatusDelete(
- mCurrentFolder,
- TEST_URI_STR,
- TEST_HANDLE_ONE,
- BluetoothMapAppParams.STATUS_VALUE_NO));
+ assertThat(
+ mObserver.setEmailMessageStatusDelete(
+ mCurrentFolder,
+ TEST_URI_STR,
+ TEST_HANDLE_ONE,
+ BluetoothMapAppParams.STATUS_VALUE_NO))
+ .isTrue();
Assert.assertEquals(msg.folderId, TEST_INBOX_FOLDER_ID);
}
@@ -813,12 +821,13 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setEmailMessageStatusDelete(
- mCurrentFolder,
- TEST_URI_STR,
- TEST_HANDLE_ONE,
- BluetoothMapAppParams.STATUS_VALUE_NO));
+ assertThat(
+ mObserver.setEmailMessageStatusDelete(
+ mCurrentFolder,
+ TEST_URI_STR,
+ TEST_HANDLE_ONE,
+ BluetoothMapAppParams.STATUS_VALUE_NO))
+ .isTrue();
Assert.assertEquals(msg.folderId, TEST_OLD_FOLDER_ID);
}
@@ -836,24 +845,26 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverUpdate(any(), any(), any(), any(), any());
- Assert.assertTrue(
- mObserver.setMessageStatusDeleted(
- TEST_HANDLE_ONE,
- TYPE.EMAIL,
- mCurrentFolder,
- TEST_URI_STR,
- BluetoothMapAppParams.STATUS_VALUE_YES));
+ assertThat(
+ mObserver.setMessageStatusDeleted(
+ TEST_HANDLE_ONE,
+ TYPE.EMAIL,
+ mCurrentFolder,
+ TEST_URI_STR,
+ BluetoothMapAppParams.STATUS_VALUE_YES))
+ .isTrue();
}
@Test
public void setMessageStatusDeleted_withTypeIm() {
- Assert.assertFalse(
- mObserver.setMessageStatusDeleted(
- TEST_HANDLE_ONE,
- TYPE.IM,
- mCurrentFolder,
- TEST_URI_STR,
- BluetoothMapAppParams.STATUS_VALUE_YES));
+ assertThat(
+ mObserver.setMessageStatusDeleted(
+ TEST_HANDLE_ONE,
+ TYPE.IM,
+ mCurrentFolder,
+ TEST_URI_STR,
+ BluetoothMapAppParams.STATUS_VALUE_YES))
+ .isFalse();
}
@Test
@@ -867,20 +878,22 @@ public class BluetoothMapContentObserverTest {
// setMessageStatusDeleted with type Gsm or Mms calls either deleteMessage() or
// unDeleteMessage(), which returns false when no cursor is set with BluetoothMethodProxy.
- Assert.assertFalse(
- mObserver.setMessageStatusDeleted(
- TEST_HANDLE_ONE,
- TYPE.MMS,
- mCurrentFolder,
- TEST_URI_STR,
- BluetoothMapAppParams.STATUS_VALUE_NO));
- Assert.assertFalse(
- mObserver.setMessageStatusDeleted(
- TEST_HANDLE_ONE,
- TYPE.SMS_GSM,
- mCurrentFolder,
- TEST_URI_STR,
- BluetoothMapAppParams.STATUS_VALUE_NO));
+ assertThat(
+ mObserver.setMessageStatusDeleted(
+ TEST_HANDLE_ONE,
+ TYPE.MMS,
+ mCurrentFolder,
+ TEST_URI_STR,
+ BluetoothMapAppParams.STATUS_VALUE_NO))
+ .isFalse();
+ assertThat(
+ mObserver.setMessageStatusDeleted(
+ TEST_HANDLE_ONE,
+ TYPE.SMS_GSM,
+ mCurrentFolder,
+ TEST_URI_STR,
+ BluetoothMapAppParams.STATUS_VALUE_NO))
+ .isFalse();
}
@Test
@@ -894,20 +907,22 @@ public class BluetoothMapContentObserverTest {
// setMessageStatusDeleted with type Gsm or Mms calls either deleteMessage() or
// unDeleteMessage(), which returns false when no cursor is set with BluetoothMethodProxy.
- Assert.assertFalse(
- mObserver.setMessageStatusDeleted(
- TEST_HANDLE_ONE,
- TYPE.MMS,
- mCurrentFolder,
- TEST_URI_STR,
- BluetoothMapAppParams.STATUS_VALUE_YES));
- Assert.assertFalse(
- mObserver.setMessageStatusDeleted(
- TEST_HANDLE_ONE,
- TYPE.SMS_GSM,
- mCurrentFolder,
- TEST_URI_STR,
- BluetoothMapAppParams.STATUS_VALUE_YES));
+ assertThat(
+ mObserver.setMessageStatusDeleted(
+ TEST_HANDLE_ONE,
+ TYPE.MMS,
+ mCurrentFolder,
+ TEST_URI_STR,
+ BluetoothMapAppParams.STATUS_VALUE_YES))
+ .isFalse();
+ assertThat(
+ mObserver.setMessageStatusDeleted(
+ TEST_HANDLE_ONE,
+ TYPE.SMS_GSM,
+ mCurrentFolder,
+ TEST_URI_STR,
+ BluetoothMapAppParams.STATUS_VALUE_YES))
+ .isFalse();
}
@Test
@@ -1459,60 +1474,7 @@ public class BluetoothMapContentObserverTest {
}
@Test
- public void handleMsgListChangesMms_withNonExistingOldMessage_andVersion12() {
- mSetFlagsRule.disableFlags(Flags.FLAG_MAP_LIMIT_NOTIFICATION);
- Calendar cal = Calendar.getInstance();
- cal.add(Calendar.YEAR, -1);
- cal.add(Calendar.DATE, -1);
- long timestampSec = TimeUnit.MILLISECONDS.toSeconds(cal.getTimeInMillis());
-
- MatrixCursor cursor =
- new MatrixCursor(
- new String[] {
- Mms._ID,
- Mms.MESSAGE_BOX,
- Mms.MESSAGE_TYPE,
- Mms.THREAD_ID,
- Mms.READ,
- Mms.DATE,
- Mms.SUBJECT,
- Mms.PRIORITY,
- Mms.Addr.ADDRESS
- });
- cursor.addRow(
- new Object[] {
- TEST_HANDLE_ONE,
- TEST_MMS_TYPE_ALL,
- TEST_MMS_MTYPE,
- TEST_THREAD_ID,
- TEST_READ_FLAG_ONE,
- timestampSec,
- TEST_SUBJECT,
- PduHeaders.PRIORITY_HIGH,
- null
- });
- doReturn(cursor)
- .when(mMapMethodProxy)
- .contentResolverQuery(any(), any(), any(), any(), any(), any());
-
- Map<Long, BluetoothMapContentObserver.Msg> map = new HashMap<>();
- // Giving a different handle for msg below and cursor above makes handleMsgListChangesMms()
- // function for a non-existing message
- BluetoothMapContentObserver.Msg msg =
- new BluetoothMapContentObserver.Msg(
- TEST_HANDLE_TWO, TEST_INBOX_FOLDER_ID, TEST_READ_FLAG_ONE);
- map.put(TEST_HANDLE_TWO, msg);
- mObserver.setMsgListMms(map, true);
- mObserver.mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V12;
-
- mObserver.handleMsgListChangesMms();
-
- Assert.assertEquals(null, mObserver.getMsgListMms().get(TEST_HANDLE_ONE));
- }
-
- @Test
public void handleMsgListChangesMms_withNonExistingOldMessage_andVersion12_andOneWeekLimit() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MAP_LIMIT_NOTIFICATION);
Instant oldInstant =
Instant.now()
.minus(BluetoothMapContentObserver.NEW_MESSAGE_DURATION_FOR_NOTIFICATION);
@@ -1861,55 +1823,7 @@ public class BluetoothMapContentObserverTest {
}
@Test
- public void handleMsgListChangesSms_withNonExistingOldMessage_andVersion12() {
- mSetFlagsRule.disableFlags(Flags.FLAG_MAP_LIMIT_NOTIFICATION);
- Calendar cal = Calendar.getInstance();
- cal.add(Calendar.YEAR, -1);
- cal.add(Calendar.DATE, -1);
-
- MatrixCursor cursor =
- new MatrixCursor(
- new String[] {
- Sms._ID,
- Sms.TYPE,
- Sms.THREAD_ID,
- Sms.READ,
- Sms.DATE,
- Sms.BODY,
- Sms.ADDRESS
- });
- cursor.addRow(
- new Object[] {
- TEST_HANDLE_ONE,
- TEST_SMS_TYPE_ALL,
- TEST_THREAD_ID,
- TEST_READ_FLAG_ONE,
- cal.getTimeInMillis(),
- "",
- null
- });
- doReturn(cursor)
- .when(mMapMethodProxy)
- .contentResolverQuery(any(), any(), any(), any(), any(), any());
-
- Map<Long, BluetoothMapContentObserver.Msg> map = new HashMap<>();
- // Giving a different handle for msg below and cursor above makes handleMsgListChangesMms()
- // function for a non-existing message
- BluetoothMapContentObserver.Msg msg =
- new BluetoothMapContentObserver.Msg(
- TEST_HANDLE_TWO, TEST_SMS_TYPE_INBOX, TEST_READ_FLAG_ONE);
- map.put(TEST_HANDLE_TWO, msg);
- mObserver.setMsgListSms(map, true);
- mObserver.mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V12;
-
- mObserver.handleMsgListChangesSms();
-
- Assert.assertEquals(null, mObserver.getMsgListSms().get(TEST_HANDLE_ONE));
- }
-
- @Test
public void handleMsgListChangesSms_withNonExistingOldMessage_andVersion12_andOneWeekLimit() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MAP_LIMIT_NOTIFICATION);
Instant oldInstant =
Instant.now()
.minus(BluetoothMapContentObserver.NEW_MESSAGE_DURATION_FOR_NOTIFICATION);
@@ -2091,7 +2005,7 @@ public class BluetoothMapContentObserverTest {
public void handleMmsSendIntent_withMnsClientNotConnected() {
when(mClient.isConnected()).thenReturn(false);
- Assert.assertFalse(mObserver.handleMmsSendIntent(mContext, mIntent));
+ assertThat(mObserver.handleMmsSendIntent(mContext, mIntent)).isFalse();
}
@Test
@@ -2101,7 +2015,7 @@ public class BluetoothMapContentObserverTest {
.when(mIntent)
.getLongExtra(BluetoothMapContentObserver.EXTRA_MESSAGE_SENT_HANDLE, -1);
- Assert.assertTrue(mObserver.handleMmsSendIntent(mContext, mIntent));
+ assertThat(mObserver.handleMmsSendIntent(mContext, mIntent)).isTrue();
}
@Test
@@ -2120,7 +2034,7 @@ public class BluetoothMapContentObserverTest {
.getIntExtra(BluetoothMapContentObserver.EXTRA_MESSAGE_SENT_TRANSPARENT, 0);
mObserver.mObserverRegistered = true;
- Assert.assertTrue(mObserver.handleMmsSendIntent(mContext, mIntent));
+ assertThat(mObserver.handleMmsSendIntent(mContext, mIntent)).isTrue();
}
@Test
@@ -2139,7 +2053,7 @@ public class BluetoothMapContentObserverTest {
.when(mMapMethodProxy)
.contentResolverDelete(any(), any(), any(), any());
- Assert.assertTrue(mObserver.handleMmsSendIntent(mContext, mIntent));
+ assertThat(mObserver.handleMmsSendIntent(mContext, mIntent)).isTrue();
}
@Test
@@ -2160,7 +2074,7 @@ public class BluetoothMapContentObserverTest {
mObserver.actionMessageSentDisconnected(mContext, mIntent, 1);
- Assert.assertTrue(mmsMsgList.containsKey(TEST_HANDLE_ONE));
+ assertThat(mmsMsgList.containsKey(TEST_HANDLE_ONE)).isTrue();
}
@Test
@@ -2197,7 +2111,7 @@ public class BluetoothMapContentObserverTest {
mObserver.actionMmsSent(mContext, mIntent, 1, mmsMsgList);
- Assert.assertTrue(mmsMsgList.containsKey(TEST_HANDLE_ONE));
+ assertThat(mmsMsgList.containsKey(TEST_HANDLE_ONE)).isTrue();
}
@Test
@@ -2218,7 +2132,7 @@ public class BluetoothMapContentObserverTest {
mObserver.actionMmsSent(mContext, mIntent, 1, mmsMsgList);
- Assert.assertFalse(mmsMsgList.containsKey(TEST_HANDLE_ONE));
+ assertThat(mmsMsgList).doesNotContainKey(TEST_HANDLE_ONE);
}
@Test
@@ -2244,7 +2158,7 @@ public class BluetoothMapContentObserverTest {
mObserver.actionMmsSent(mContext, mIntent, Activity.RESULT_OK, mmsMsgList);
- Assert.assertTrue(mmsMsgList.containsKey(TEST_HANDLE_ONE));
+ assertThat(mmsMsgList.containsKey(TEST_HANDLE_ONE)).isTrue();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
index 2da0f14a2d..e6716b487c 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.mapclient;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import androidx.test.filters.MediumTest;
@@ -59,39 +61,33 @@ public class BmessageTest {
@Test
public void testNormalMessages() {
- Bmessage message = BmessageParser.createBmessage(SIMPLE_MMS_MESSAGE);
- Assert.assertNotNull(message);
+ assertThat(BmessageParser.createBmessage(SIMPLE_MMS_MESSAGE)).isNotNull();
}
@Test
public void testParseWrongLengthMessage() {
- Bmessage message = BmessageParser.createBmessage(WRONG_LENGTH_MESSAGE);
- Assert.assertNull(message);
+ assertThat(BmessageParser.createBmessage(WRONG_LENGTH_MESSAGE)).isNull();
}
@Test
public void testParseNoEndMessage() {
- Bmessage message = BmessageParser.createBmessage(NO_END_MESSAGE);
- Assert.assertNull(message);
+ assertThat(BmessageParser.createBmessage(NO_END_MESSAGE)).isNull();
}
@Test
public void testParseReallyLongMessage() {
String testMessage = new String(new char[68048]).replace('\0', 'A');
- Bmessage message = BmessageParser.createBmessage(testMessage);
- Assert.assertNull(message);
+ assertThat(BmessageParser.createBmessage(testMessage)).isNull();
}
@Test
public void testNoBodyMessage() {
- Bmessage message = BmessageParser.createBmessage(NO_BODY_MESSAGE);
- Assert.assertNull(message);
+ assertThat(BmessageParser.createBmessage(NO_BODY_MESSAGE)).isNull();
}
@Test
public void testNegativeLengthMessage() {
- Bmessage message = BmessageParser.createBmessage(NEGATIVE_LENGTH_MESSAGE);
- Assert.assertNull(message);
+ assertThat(BmessageParser.createBmessage(NEGATIVE_LENGTH_MESSAGE)).isNull();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
index a6dadddff2..5d4207faa5 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
@@ -108,6 +108,7 @@ public class MapClientStateMachineTest {
private Bmessage mTestIncomingMmsBmessage;
private String mTestMessageSmsHandle = "0001";
private String mTestMessageMmsHandle = "0002";
+ private String mTestMessageUnknownHandle = "0003";
boolean mIsAdapterServiceSet;
boolean mIsMapClientServiceStarted;
@@ -367,8 +368,8 @@ public class MapClientStateMachineTest {
// to MapClientService to change
// state from STATE_CONNECTING to STATE_CONNECTED
assertCurrentStateAfterScheduledTask(BluetoothProfile.STATE_CONNECTED);
- Assert.assertTrue(
- mMceStateMachine.setMessageStatus("123456789AB", BluetoothMapClient.READ));
+ assertThat(mMceStateMachine.setMessageStatus("123456789AB", BluetoothMapClient.READ))
+ .isTrue();
}
/** Test MceStateMachine#disconnect */
@@ -721,6 +722,48 @@ public class MapClientStateMachineTest {
eq(MESSAGE_NOT_SEEN));
}
+ @Test
+ public void testReceiveNewMessage_handleNotRecognized_messageDropped() {
+ setupSdpRecordReceipt();
+ Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
+ mMceStateMachine.sendMessage(msg);
+
+ // verifying that state machine is in the Connected state
+ assertCurrentStateAfterScheduledTask(BluetoothProfile.STATE_CONNECTED);
+
+ // Send new message event with handle A
+ String dateTime = new ObexTime(Instant.now()).toString();
+ EventReport event =
+ createNewEventReport(
+ "NewMessage",
+ dateTime,
+ mTestMessageMmsHandle,
+ "telecom/msg/inbox",
+ null,
+ "MMS");
+
+ // Prepare to send back message content, but use handle B
+ when(mMockRequestGetMessage.getHandle()).thenReturn(mTestMessageUnknownHandle);
+ when(mMockRequestGetMessage.getMessage()).thenReturn(mTestIncomingMmsBmessage);
+
+ mMceStateMachine.receiveEvent(event);
+
+ TestUtils.waitForLooperToBeIdle(mMceStateMachine.getHandler().getLooper());
+ verify(mMockMasClient).makeRequest(any(RequestGetMessage.class));
+
+ msg =
+ Message.obtain(
+ mHandler,
+ MceStateMachine.MSG_MAS_REQUEST_COMPLETED,
+ mMockRequestGetMessage);
+ mMceStateMachine.sendMessage(msg);
+
+ // We should drop the message and not store it, as it's not one we requested
+ TestUtils.waitForLooperToBeIdle(mMceStateMachine.getHandler().getLooper());
+ verify(mMockDatabase, never())
+ .storeMessage(any(Bmessage.class), anyString(), anyLong(), anyBoolean());
+ }
+
/** Test seen status set in database on initial download */
@Test
public void testDownloadExistingSms_messageStoredAsSeen() {
@@ -930,7 +973,7 @@ public class MapClientStateMachineTest {
verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
.sendBroadcast(
mIntentArgument.capture(), eq(android.Manifest.permission.RECEIVE_SMS));
- Assert.assertNull(mIntentArgument.getValue().getPackage());
+ assertThat(mIntentArgument.getValue().getPackage()).isNull();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
index 04ed3e5d40..4086981761 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.mapclient;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -84,7 +86,7 @@ public class MapClientTest {
mService.stop();
mService.cleanup();
mService = MapClientService.getMapClientService();
- Assert.assertNull(mService);
+ assertThat(mService).isNull();
}
if (mIsAdapterServiceSet) {
TestUtils.clearAdapterService(mAdapterService);
@@ -104,7 +106,7 @@ public class MapClientTest {
@Test
public void testInitialize() {
- Assert.assertNotNull(MapClientService.getMapClientService());
+ assertThat(MapClientService.getMapClientService()).isNotNull();
}
/** Test connection of one device. */
@@ -112,23 +114,23 @@ public class MapClientTest {
public void testConnect() {
// make sure there is no statemachine already defined for this device
BluetoothDevice device = makeBluetoothDevice("11:11:11:11:11:11");
- Assert.assertNull(mService.getInstanceMap().get(device));
+ assertThat(mService.getInstanceMap()).doesNotContainKey(device);
// connect a bluetooth device
mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- Assert.assertTrue(mService.connect(device));
+ assertThat(mService.connect(device)).isTrue();
// is the statemachine created
Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
Assert.assertEquals(1, map.size());
MceStateMachine sm = map.get(device);
- Assert.assertNotNull(sm);
+ assertThat(sm).isNotNull();
TestUtils.waitForLooperToFinishScheduledTask(sm.getHandler().getLooper());
Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, sm.getState());
mService.cleanupDevice(device, sm);
- Assert.assertNull(mService.getInstanceMap().get(device));
+ assertThat(mService.getInstanceMap()).doesNotContainKey(device);
}
/** Test that a PRIORITY_OFF device is not connected to */
@@ -136,16 +138,14 @@ public class MapClientTest {
public void testConnectPriorityOffDevice() {
// make sure there is no statemachine already defined for this device
BluetoothDevice device = makeBluetoothDevice("11:11:11:11:11:11");
- Assert.assertNull(mService.getInstanceMap().get(device));
+ assertThat(mService.getInstanceMap()).doesNotContainKey(device);
// connect a bluetooth device
mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
- Assert.assertFalse(mService.connect(device));
+ assertThat(mService.connect(device)).isFalse();
// is the statemachine created
- Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
- Assert.assertEquals(0, map.size());
- Assert.assertNull(map.get(device));
+ assertThat(mService.getInstanceMap()).isEmpty();
}
/** Test connecting MAXIMUM_CONNECTED_DEVICES devices. */
@@ -160,25 +160,25 @@ public class MapClientTest {
// make sure there is no statemachine already defined for the devices defined above
for (BluetoothDevice d : list) {
- Assert.assertNull(mService.getInstanceMap().get(d));
+ assertThat(mService.getInstanceMap().get(d)).isNull();
}
// run the test - connect all devices, set their priorities to on
for (BluetoothDevice d : list) {
mockDevicePriority(d, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- Assert.assertTrue(mService.connect(d));
+ assertThat(mService.connect(d)).isTrue();
}
// verify
Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
Assert.assertEquals(MapClientService.MAXIMUM_CONNECTED_DEVICES, map.size());
for (BluetoothDevice d : list) {
- Assert.assertNotNull(map.get(d));
+ assertThat(map).containsKey(d);
}
// Try to connect one more device. Should fail.
BluetoothDevice last = makeBluetoothDevice("11:22:33:44:55:66");
- Assert.assertFalse(mService.connect(last));
+ assertThat(mService.connect(last)).isFalse();
}
/** Test calling connect via Binder */
@@ -186,12 +186,8 @@ public class MapClientTest {
public void testConnectViaBinder() {
BluetoothDevice device = makeBluetoothDevice("11:11:11:11:11:11");
mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- try {
- Utils.setForegroundUserId(UserHandle.getCallingUserId());
- Assert.assertTrue(mService.connect(device));
- } catch (Exception e) {
- Assert.fail(e.toString());
- }
+ Utils.setForegroundUserId(UserHandle.getCallingUserId());
+ assertThat(mService.connect(device)).isTrue();
}
private BluetoothDevice makeBluetoothDevice(String address) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceTest.java
index 2f2bf7f064..dd9e61ae7f 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceTest.java
@@ -17,6 +17,8 @@
package com.android.bluetooth.mcp;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -77,7 +79,7 @@ public class McpServiceTest {
mMcpService.stop();
mMcpService = McpService.getMcpService();
- Assert.assertNull(mMcpService);
+ assertThat(mMcpService).isNull();
reset(mMediaControlProfile);
TestUtils.clearAdapterService(mAdapterService);
}
@@ -85,7 +87,7 @@ public class McpServiceTest {
@Test
public void testGetService() {
McpService mMcpServiceDuplicate = McpService.getMcpService();
- Assert.assertNotNull(mMcpServiceDuplicate);
+ assertThat(mMcpServiceDuplicate).isNotNull();
Assert.assertSame(mMcpServiceDuplicate, mMcpService);
}
@@ -110,7 +112,7 @@ public class McpServiceTest {
@Test
public void testStopMcpService() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(mMcpService::stop);
- Assert.assertNull(McpService.getMcpService());
+ assertThat(McpService.getMcpService()).isNull();
// Try to restart the service. Note: must be done on the main thread
InstrumentationRegistry.getInstrumentation().runOnMainSync(mMcpService::start);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlGattServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlGattServiceTest.java
index 03fbe7f71a..3da40b9bbd 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlGattServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlGattServiceTest.java
@@ -17,6 +17,8 @@
package com.android.bluetooth.mcp;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -132,7 +134,7 @@ public class MediaControlGattServiceTest {
long mMandatoryFeatures = ServiceFeature.ALL_MANDATORY_SERVICE_FEATURES;
doReturn(mMandatoryFeatures).when(mMockMcsCallbacks).onGetFeatureFlags();
- Assert.assertTrue(mMcpService.init(UUID_GMCS));
+ assertThat(mMcpService.init(UUID_GMCS)).isTrue();
Assert.assertEquals(mMcpService.getServiceUuid(), UUID_GMCS);
Assert.assertEquals(mMcpService.getContentControlId(), TEST_CCID);
@@ -146,7 +148,7 @@ public class MediaControlGattServiceTest {
long mMandatoryFeatures = 0;
doReturn(mMandatoryFeatures).when(mMockMcsCallbacks).onGetFeatureFlags();
- Assert.assertFalse(mMcpService.init(UUID_GMCS));
+ assertThat(mMcpService.init(UUID_GMCS)).isFalse();
}
private BluetoothGattService initAllFeaturesGattService() {
@@ -182,13 +184,13 @@ public class MediaControlGattServiceTest {
| ServiceFeature.MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY;
doReturn(features).when(mMockMcsCallbacks).onGetFeatureFlags();
- Assert.assertTrue(mMcpService.init(UUID_GMCS));
+ assertThat(mMcpService.init(UUID_GMCS)).isTrue();
verify(mMockGattServer).addService(mGattServiceCaptor.capture());
// Capture GATT Service definition for verification
BluetoothGattService service = mGattServiceCaptor.getValue();
- Assert.assertNotNull(service);
+ assertThat(service).isNotNull();
// Call back the low level GATT callback and expect proper higher level callback to be
// called
@@ -207,7 +209,7 @@ public class MediaControlGattServiceTest {
// Check initial state of all mandatory characteristics
BluetoothGattCharacteristic characteristic =
service.getCharacteristic(MediaControlGattService.UUID_PLAYER_NAME);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -215,7 +217,7 @@ public class MediaControlGattServiceTest {
Assert.assertEquals("", characteristic.getStringValue(0));
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_TITLE);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -223,7 +225,7 @@ public class MediaControlGattServiceTest {
Assert.assertEquals("", characteristic.getStringValue(0));
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_DURATION);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -235,7 +237,7 @@ public class MediaControlGattServiceTest {
.intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_POSITION);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -249,7 +251,7 @@ public class MediaControlGattServiceTest {
.intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_MEDIA_STATE);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -259,7 +261,7 @@ public class MediaControlGattServiceTest {
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0).intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_CONTENT_CONTROL_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(), BluetoothGattCharacteristic.PROPERTY_READ);
Assert.assertEquals(
@@ -268,24 +270,24 @@ public class MediaControlGattServiceTest {
// Check initial state of all optional characteristics
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYER_ICON_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(), BluetoothGattCharacteristic.PROPERTY_READ);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYER_ICON_URL);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(), BluetoothGattCharacteristic.PROPERTY_READ);
Assert.assertEquals("", characteristic.getStringValue(0));
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_CHANGED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(), BluetoothGattCharacteristic.PROPERTY_NOTIFY);
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYBACK_SPEED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -297,7 +299,7 @@ public class MediaControlGattServiceTest {
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0).intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_SEEKING_SPEED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -309,54 +311,54 @@ public class MediaControlGattServiceTest {
characteristic =
service.getCharacteristic(
MediaControlGattService.UUID_CURRENT_TRACK_SEGMENT_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(), BluetoothGattCharacteristic.PROPERTY_READ);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_CURRENT_TRACK_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_WRITE
| BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
| BluetoothGattCharacteristic.PROPERTY_NOTIFY);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic = service.getCharacteristic(MediaControlGattService.UUID_NEXT_TRACK_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_WRITE
| BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
| BluetoothGattCharacteristic.PROPERTY_NOTIFY);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_CURRENT_GROUP_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_WRITE
| BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
| BluetoothGattCharacteristic.PROPERTY_NOTIFY);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_PARENT_GROUP_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_NOTIFY);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYING_ORDER);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -369,7 +371,7 @@ public class MediaControlGattServiceTest {
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_PLAYING_ORDER_SUPPORTED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(), BluetoothGattCharacteristic.PROPERTY_READ);
Assert.assertEquals(
@@ -380,7 +382,7 @@ public class MediaControlGattServiceTest {
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_MEDIA_CONTROL_POINT);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_NOTIFY
@@ -390,7 +392,7 @@ public class MediaControlGattServiceTest {
characteristic =
service.getCharacteristic(
MediaControlGattService.UUID_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
@@ -403,16 +405,16 @@ public class MediaControlGattServiceTest {
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_SEARCH_RESULT_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_NOTIFY);
- Assert.assertTrue(characteristic.getValue().length == 0);
+ assertThat(characteristic.getValue().length).isEqualTo(0);
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_SEARCH_CONTROL_POINT);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
characteristic.getProperties(),
BluetoothGattCharacteristic.PROPERTY_NOTIFY
@@ -485,18 +487,18 @@ public class MediaControlGattServiceTest {
BluetoothGattCharacteristic characteristic =
service.getCharacteristic(MediaControlGattService.UUID_PLAYBACK_SPEED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
playback_speed, mMcpService.getPlaybackSpeedChar().floatValue(), 0.001f);
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYING_ORDER);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
playing_order.getValue(),
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0).intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_POSITION);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
// Set value as ms, kept in characteristic as 0.01s
Assert.assertEquals(
track_position / 10,
@@ -505,21 +507,21 @@ public class MediaControlGattServiceTest {
.intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYER_NAME);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(player_name, characteristic.getStringValue(0));
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYER_ICON_URL);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(icon_url, characteristic.getStringValue(0));
characteristic = service.getCharacteristic(MediaControlGattService.UUID_PLAYER_ICON_OBJ_ID);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
icon_obj_id.longValue(), mMcpService.byteArray2ObjId(characteristic.getValue()));
characteristic =
service.getCharacteristic(MediaControlGattService.UUID_PLAYING_ORDER_SUPPORTED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
playing_order_supported.intValue(),
characteristic
@@ -529,7 +531,7 @@ public class MediaControlGattServiceTest {
characteristic =
service.getCharacteristic(
MediaControlGattService.UUID_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
opcodes_supported.intValue(),
characteristic
@@ -537,11 +539,11 @@ public class MediaControlGattServiceTest {
.intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_TITLE);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(track_title, characteristic.getStringValue(0));
characteristic = service.getCharacteristic(MediaControlGattService.UUID_TRACK_DURATION);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
// Set value as ms, kept in characteristic as 0.01s
Assert.assertEquals(
track_duration / 10,
@@ -550,13 +552,13 @@ public class MediaControlGattServiceTest {
.intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_MEDIA_STATE);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(
playback_state.getValue(),
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0).intValue());
characteristic = service.getCharacteristic(MediaControlGattService.UUID_SEEKING_SPEED);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
Assert.assertEquals(seeking_speed, mMcpService.getSeekingSpeedChar().floatValue(), 0.001f);
}
@@ -1031,7 +1033,7 @@ public class MediaControlGattServiceTest {
@Test
public void testMediaControlPointRequestInvalid() {
- Assert.assertFalse(mMcpService.isOpcodeSupported(Request.Opcodes.PLAY));
+ assertThat(mMcpService.isOpcodeSupported(Request.Opcodes.PLAY)).isFalse();
}
@Test
@@ -1311,7 +1313,7 @@ public class MediaControlGattServiceTest {
BluetoothGattDescriptor descriptor =
service.getCharacteristic(MediaControlGattService.UUID_TRACK_POSITION)
.getDescriptor(UUID_CCCD);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
prepareConnectedDevice();
doReturn(BluetoothDevice.ACCESS_REJECTED)
@@ -1336,7 +1338,7 @@ public class MediaControlGattServiceTest {
BluetoothGattDescriptor descriptor =
service.getCharacteristic(MediaControlGattService.UUID_TRACK_POSITION)
.getDescriptor(UUID_CCCD);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
prepareConnectedDevice();
doReturn(BluetoothDevice.ACCESS_UNKNOWN)
@@ -1361,7 +1363,7 @@ public class MediaControlGattServiceTest {
BluetoothGattDescriptor descriptor =
service.getCharacteristic(MediaControlGattService.UUID_TRACK_POSITION)
.getDescriptor(UUID_CCCD);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
prepareConnectedDevice();
doReturn(BluetoothDevice.ACCESS_REJECTED)
@@ -1391,7 +1393,7 @@ public class MediaControlGattServiceTest {
BluetoothGattDescriptor descriptor =
service.getCharacteristic(MediaControlGattService.UUID_TRACK_POSITION)
.getDescriptor(UUID_CCCD);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
prepareConnectedDevice();
doReturn(BluetoothDevice.ACCESS_UNKNOWN)
@@ -1420,7 +1422,7 @@ public class MediaControlGattServiceTest {
BluetoothGattCharacteristic characteristic =
service.getCharacteristic(MediaControlGattService.UUID_PLAYER_NAME);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
byte[] nullname = null;
characteristic.setValue(nullname);
@@ -1441,7 +1443,7 @@ public class MediaControlGattServiceTest {
BluetoothGattCharacteristic characteristic =
service.getCharacteristic(MediaControlGattService.UUID_MEDIA_STATE);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
byte[] nullBytes = null;
characteristic.setValue(nullBytes);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlProfileTest.java b/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlProfileTest.java
index a59b94ce4a..1da98c68af 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlProfileTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mcp/MediaControlProfileTest.java
@@ -18,6 +18,8 @@ package com.android.bluetooth.mcp;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothAdapter;
@@ -251,18 +253,18 @@ public class MediaControlProfileTest {
verify(mMockGMcsService, timeout(100).times(2)).updatePlayerState(stateMapCaptor.capture());
stateMap = stateMapCaptor.getValue();
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYER_NAME));
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYER_NAME);
// state changed
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYBACK_STATE));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.OPCODES_SUPPORTED));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.SEEKING_SPEED));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYBACK_SPEED));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.TRACK_POSITION));
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYBACK_STATE);
+ assertThat(stateMap).containsKey(PlayerStateField.OPCODES_SUPPORTED);
+ assertThat(stateMap).containsKey(PlayerStateField.SEEKING_SPEED);
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYBACK_SPEED);
+ assertThat(stateMap).containsKey(PlayerStateField.TRACK_POSITION);
// metadata changed
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.TRACK_DURATION));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.TRACK_TITLE));
+ assertThat(stateMap).containsKey(PlayerStateField.TRACK_DURATION);
+ assertThat(stateMap).containsKey(PlayerStateField.TRACK_TITLE);
}
private void testHandleTrackPositionSetRequest(long position, long duration, int times) {
@@ -464,15 +466,15 @@ public class MediaControlProfileTest {
verify(mMockGMcsService, timeout(100).times(2)).updatePlayerState(stateMapCaptor.capture());
stateMap = stateMapCaptor.getValue();
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYBACK_STATE));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.TRACK_DURATION));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYBACK_SPEED));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.SEEKING_SPEED));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYING_ORDER));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.TRACK_POSITION));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYER_NAME));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.PLAYING_ORDER_SUPPORTED));
- Assert.assertTrue(stateMap.containsKey(PlayerStateField.OPCODES_SUPPORTED));
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYBACK_STATE);
+ assertThat(stateMap).containsKey(PlayerStateField.TRACK_DURATION);
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYBACK_SPEED);
+ assertThat(stateMap).containsKey(PlayerStateField.SEEKING_SPEED);
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYING_ORDER);
+ assertThat(stateMap).containsKey(PlayerStateField.TRACK_POSITION);
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYER_NAME);
+ assertThat(stateMap).containsKey(PlayerStateField.PLAYING_ORDER_SUPPORTED);
+ assertThat(stateMap).containsKey(PlayerStateField.OPCODES_SUPPORTED);
}
private void testGetCurrentPlayerPlayingOrder(
@@ -526,8 +528,8 @@ public class MediaControlProfileTest {
// BluetoothDevice class is not mockable
BluetoothDevice bluetoothDevice = TestUtils.getTestDevice(mAdapter, 0);
mMediaControlProfile.setNotificationSubscription(ccid1, bluetoothDevice, charUuid1, true);
- Assert.assertNotNull(
- mMediaControlProfile.getNotificationSubscriptions(ccid1, bluetoothDevice));
+ assertThat(mMediaControlProfile.getNotificationSubscriptions(ccid1, bluetoothDevice))
+ .isNotNull();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppReceiverTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppReceiverTest.java
index 7b6c5f7344..9683a02fac 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppReceiverTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppReceiverTest.java
@@ -42,7 +42,6 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
-import android.platform.test.flag.junit.SetFlagsRule;
import android.sysprop.BluetoothProperties;
import androidx.test.espresso.intent.Intents;
@@ -51,7 +50,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.TestUtils;
-import com.android.bluetooth.flags.Flags;
import com.google.common.base.Objects;
@@ -71,8 +69,6 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class BluetoothOppReceiverTest {
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
Context mContext;
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@@ -132,24 +128,6 @@ public class BluetoothOppReceiverTest {
}
@Test
- public void onReceive_withActionIncomingFileConfirm_startsIncomingFileConfirmActivity() {
- mSetFlagsRule.disableFlags(Flags.FLAG_OPP_START_ACTIVITY_DIRECTLY_FROM_NOTIFICATION);
- try {
- BluetoothOppTestUtils.enableActivity(
- BluetoothOppIncomingFileConfirmActivity.class, true, mContext);
-
- Intent intent = new Intent();
- intent.setAction(Constants.ACTION_INCOMING_FILE_CONFIRM);
- intent.setData(Uri.parse("content:///not/important"));
- mReceiver.onReceive(mContext, intent);
- intended(hasComponent(BluetoothOppIncomingFileConfirmActivity.class.getName()));
- } finally {
- BluetoothOppTestUtils.enableActivity(
- BluetoothOppIncomingFileConfirmActivity.class, false, mContext);
- }
- }
-
- @Test
public void onReceive_withActionAccept_updatesContents() {
Uri uri = Uri.parse("content:///important");
Intent intent = new Intent();
@@ -190,49 +168,6 @@ public class BluetoothOppReceiverTest {
}
@Test
- public void onReceive_withActionOutboundTransfer_startsTransferHistoryActivity() {
- mSetFlagsRule.disableFlags(Flags.FLAG_OPP_START_ACTIVITY_DIRECTLY_FROM_NOTIFICATION);
- try {
- BluetoothOppTestUtils.enableActivity(BluetoothOppTransferHistory.class, true, mContext);
-
- Intent intent = new Intent();
- intent.setAction(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
- intent.setData(Uri.parse("content:///not/important"));
- intending(anyIntent())
- .respondWith(
- new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent()));
-
- mReceiver.onReceive(mContext, intent);
- intended(hasComponent(BluetoothOppTransferHistory.class.getName()));
- intended(hasExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_OUTBOUND));
- } finally {
- BluetoothOppTestUtils.enableActivity(
- BluetoothOppTransferHistory.class, false, mContext);
- }
- }
-
- @Test
- public void onReceive_withActionInboundTransfer_startsTransferHistoryActivity() {
- mSetFlagsRule.disableFlags(Flags.FLAG_OPP_START_ACTIVITY_DIRECTLY_FROM_NOTIFICATION);
- try {
- BluetoothOppTestUtils.enableActivity(BluetoothOppTransferHistory.class, true, mContext);
-
- Intent intent = new Intent();
- intent.setAction(Constants.ACTION_OPEN_INBOUND_TRANSFER);
- intent.setData(Uri.parse("content:///not/important"));
- intending(anyIntent())
- .respondWith(
- new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent()));
- mReceiver.onReceive(mContext, intent);
- intended(hasComponent(BluetoothOppTransferHistory.class.getName()));
- intended(hasExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_INBOUND));
- } finally {
- BluetoothOppTestUtils.enableActivity(
- BluetoothOppTransferHistory.class, false, mContext);
- }
- }
-
- @Test
public void onReceive_withActionHide_contentUpdate() {
List<BluetoothOppTestUtils.CursorMockData> cursorMockDataList;
Cursor cursor = mock(Cursor.class);
@@ -273,27 +208,7 @@ public class BluetoothOppReceiverTest {
}
@Test
- public void onReceive_withActionCompleteHide_makeAllVisibilityHidden() {
- mSetFlagsRule.disableFlags(Flags.FLAG_OPP_FIX_MULTIPLE_NOTIFICATIONS_ISSUES);
- Intent intent = new Intent();
- intent.setAction(Constants.ACTION_COMPLETE_HIDE);
- mReceiver.onReceive(mContext, intent);
- verify(mBluetoothMethodProxy)
- .contentResolverUpdate(
- any(),
- eq(BluetoothShare.CONTENT_URI),
- argThat(
- arg ->
- Objects.equal(
- BluetoothShare.VISIBILITY_HIDDEN,
- arg.get(BluetoothShare.VISIBILITY))),
- any(),
- any());
- }
-
- @Test
public void onReceive_withActionHideCompletedInboundTransfer_makesInboundVisibilityHidden() {
- mSetFlagsRule.enableFlags(Flags.FLAG_OPP_FIX_MULTIPLE_NOTIFICATIONS_ISSUES);
Intent intent = new Intent();
intent.setAction(Constants.ACTION_HIDE_COMPLETED_INBOUND_TRANSFER);
mReceiver.onReceive(mContext, intent);
@@ -312,7 +227,6 @@ public class BluetoothOppReceiverTest {
@Test
public void onReceive_withActionHideCompletedOutboundTransfer_makesOutboundVisibilityHidden() {
- mSetFlagsRule.enableFlags(Flags.FLAG_OPP_FIX_MULTIPLE_NOTIFICATIONS_ISSUES);
Intent intent = new Intent();
intent.setAction(Constants.ACTION_HIDE_COMPLETED_OUTBOUND_TRANSFER);
mReceiver.onReceive(mContext, intent);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppSendFileInfoTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppSendFileInfoTest.java
index 273f6fd8d5..aad8a31170 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppSendFileInfoTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppSendFileInfoTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.opp;
+import static android.os.UserHandle.myUserId;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -120,6 +122,110 @@ public class BluetoothOppSendFileInfoTest {
}
@Test
+ public void generateFileInfo_withContentUriForOtherUser_returnsSendFileInfoError()
+ throws Exception {
+ String type = "image/jpeg";
+ Uri uri = buildContentUriWithEncodedAuthority((myUserId() + 1) + "@media");
+
+ long fileLength = 1000;
+ String fileName = "pic.jpg";
+
+ FileInputStream fs = mock(FileInputStream.class);
+ AssetFileDescriptor fd = mock(AssetFileDescriptor.class);
+ doReturn(fileLength).when(fd).getLength();
+ doReturn(fs).when(fd).createInputStream();
+
+ doReturn(fd).when(mCallProxy).contentResolverOpenAssetFileDescriptor(any(), eq(uri), any());
+
+ mCursor =
+ new MatrixCursor(new String[] {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE});
+ mCursor.addRow(new Object[] {fileName, fileLength});
+
+ doReturn(mCursor)
+ .when(mCallProxy)
+ .contentResolverQuery(any(), eq(uri), any(), any(), any(), any());
+
+ BluetoothOppSendFileInfo info =
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, type, true);
+
+ assertThat(info).isEqualTo(BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
+ }
+
+ @Test
+ public void generateFileInfo_withContentUriForImplicitUser_returnsInfoWithCorrectLength()
+ throws Exception {
+ String type = "image/jpeg";
+ Uri uri = buildContentUriWithEncodedAuthority("media");
+
+ long fileLength = 1000;
+ String fileName = "pic.jpg";
+
+ FileInputStream fs = mock(FileInputStream.class);
+ AssetFileDescriptor fd = mock(AssetFileDescriptor.class);
+ doReturn(fileLength).when(fd).getLength();
+ doReturn(fs).when(fd).createInputStream();
+
+ doReturn(fd).when(mCallProxy).contentResolverOpenAssetFileDescriptor(any(), eq(uri), any());
+
+ mCursor =
+ new MatrixCursor(new String[] {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE});
+ mCursor.addRow(new Object[] {fileName, fileLength});
+
+ doReturn(mCursor)
+ .when(mCallProxy)
+ .contentResolverQuery(any(), eq(uri), any(), any(), any(), any());
+
+ BluetoothOppSendFileInfo info =
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, type, true);
+
+ assertThat(info.mInputStream).isEqualTo(fs);
+ assertThat(info.mFileName).isEqualTo(fileName);
+ assertThat(info.mLength).isEqualTo(fileLength);
+ assertThat(info.mStatus).isEqualTo(0);
+ }
+
+ @Test
+ public void generateFileInfo_withContentUriForSameUser_returnsInfoWithCorrectLength()
+ throws Exception {
+ String type = "image/jpeg";
+ Uri uri = buildContentUriWithEncodedAuthority(myUserId() + "@media");
+
+ long fileLength = 1000;
+ String fileName = "pic.jpg";
+
+ FileInputStream fs = mock(FileInputStream.class);
+ AssetFileDescriptor fd = mock(AssetFileDescriptor.class);
+ doReturn(fileLength).when(fd).getLength();
+ doReturn(fs).when(fd).createInputStream();
+
+ doReturn(fd).when(mCallProxy).contentResolverOpenAssetFileDescriptor(any(), eq(uri), any());
+
+ mCursor =
+ new MatrixCursor(new String[] {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE});
+ mCursor.addRow(new Object[] {fileName, fileLength});
+
+ doReturn(mCursor)
+ .when(mCallProxy)
+ .contentResolverQuery(any(), eq(uri), any(), any(), any(), any());
+
+ BluetoothOppSendFileInfo info =
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, type, true);
+
+ assertThat(info.mInputStream).isEqualTo(fs);
+ assertThat(info.mFileName).isEqualTo(fileName);
+ assertThat(info.mLength).isEqualTo(fileLength);
+ assertThat(info.mStatus).isEqualTo(0);
+ }
+
+ private static Uri buildContentUriWithEncodedAuthority(String authority) {
+ return new Uri.Builder()
+ .scheme("content")
+ .encodedAuthority(authority)
+ .path("external/images/media/1")
+ .build();
+ }
+
+ @Test
public void generateFileInfo_withoutPermissionForAccessingUri_returnsSendFileInfoError() {
String type = "text/plain";
Uri uri = Uri.parse("content:///hello/world");
diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java
index 4b5bd23465..7e54701383 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceTest.java
@@ -42,7 +42,6 @@ import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.btservice.AdapterService;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -121,7 +120,7 @@ public class BluetoothOppServiceTest {
@Test
public void testInitialize() {
- Assert.assertNotNull(BluetoothOppService.getBluetoothOppService());
+ assertThat(BluetoothOppService.getBluetoothOppService()).isNotNull();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferHistoryTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferHistoryTest.java
index e336cd354b..69d01b2853 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferHistoryTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferHistoryTest.java
@@ -44,7 +44,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
-import com.android.bluetooth.flags.Flags;
import com.google.common.base.Objects;
@@ -155,11 +154,7 @@ public class BluetoothOppTransferHistoryTest {
mTargetContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
BluetoothOppTestUtils.setUpMockCursor(mCursor, mCursorMockDataList);
- if (Flags.oppStartActivityDirectlyFromNotification()) {
- mIntent.setAction(Constants.ACTION_OPEN_INBOUND_TRANSFER);
- } else {
- mIntent.putExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_INBOUND);
- }
+ mIntent.setAction(Constants.ACTION_OPEN_INBOUND_TRANSFER);
ActivityScenario.launch(mIntent);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -178,11 +173,7 @@ public class BluetoothOppTransferHistoryTest {
1,
new BluetoothOppTestUtils.CursorMockData(
BluetoothShare.DIRECTION, 2, BluetoothShare.DIRECTION_OUTBOUND));
- if (Flags.oppStartActivityDirectlyFromNotification()) {
- mIntent.setAction(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
- } else {
- mIntent.putExtra(Constants.EXTRA_DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
- }
+ mIntent.setAction(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
ActivityScenario.launch(mIntent);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
index c0f52ee602..41dac6b274 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
@@ -59,7 +59,6 @@ import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.flags.Flags;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -170,7 +169,7 @@ public class PbapClientServiceTest {
.getStorageAccountForDevice(any(BluetoothDevice.class));
mAdapter = BluetoothAdapter.getDefaultAdapter();
- Assert.assertNotNull(mAdapter);
+ assertThat(mAdapter).isNotNull();
mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);
if (Looper.myLooper() == null) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGattTest.java b/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGattTest.java
index 2e5e12ffd5..798984b273 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGattTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGattTest.java
@@ -19,6 +19,9 @@ package com.android.bluetooth.tbs;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.mockito.AdditionalMatchers.*;
import static org.mockito.Mockito.*;
@@ -125,28 +128,27 @@ public class TbsGattTest {
mCurrentProviderName = "unknown";
mCurrentTechnology = 0x00;
- Assert.assertTrue(
- mTbsGatt.init(
- mCurrentCcid,
- mCurrentUci,
- mCurrentUriSchemes,
- true,
- true,
- mCurrentProviderName,
- mCurrentTechnology,
- mMockTbsGattCallback));
- Assert.assertNotNull(mMockGattServer);
+ assertThat(
+ mTbsGatt.init(
+ mCurrentCcid,
+ mCurrentUci,
+ mCurrentUriSchemes,
+ true,
+ true,
+ mCurrentProviderName,
+ mCurrentTechnology,
+ mMockTbsGattCallback))
+ .isTrue();
verify(mAdapterService).registerBluetoothStateCallback(any(), any());
verify(mMockGattServer).addService(mGattServiceCaptor.capture());
doReturn(mGattServiceCaptor.getValue()).when(mMockGattServer).getService(any(UUID.class));
- Assert.assertNotNull(mMockGattServer);
}
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattService service = mGattServiceCaptor.getValue();
BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid);
- Assert.assertNotNull(characteristic);
+ assertThat(characteristic).isNotNull();
return characteristic;
}
@@ -155,7 +157,7 @@ public class TbsGattTest {
BluetoothDevice device, BluetoothGattCharacteristic characteristic, boolean enable) {
BluetoothGattDescriptor descriptor =
characteristic.getDescriptor(TbsGatt.UUID_CLIENT_CHARACTERISTIC_CONFIGURATION);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
mTbsGatt.mGattServerCallback.onDescriptorWriteRequest(
device,
@@ -183,14 +185,14 @@ public class TbsGattTest {
if (characteristic.getUuid().equals(TbsGatt.UUID_BEARER_PROVIDER_NAME)) {
boolean valueChanged = !characteristic.getStringValue(0).equals((String) value);
if (valueChanged) {
- Assert.assertTrue(mTbsGatt.setBearerProviderName((String) value));
+ assertThat(mTbsGatt.setBearerProviderName((String) value)).isTrue();
} else {
- Assert.assertFalse(mTbsGatt.setBearerProviderName((String) value));
+ assertThat(mTbsGatt.setBearerProviderName((String) value)).isFalse();
}
Assert.assertEquals((String) value, characteristic.getStringValue(0));
} else if (characteristic.getUuid().equals(TbsGatt.UUID_BEARER_TECHNOLOGY)) {
- Assert.assertTrue(mTbsGatt.setBearerTechnology((Integer) value));
+ assertThat(mTbsGatt.setBearerTechnology((Integer) value)).isTrue();
Assert.assertEquals(
(Integer) value,
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));
@@ -201,9 +203,11 @@ public class TbsGattTest {
String valueString = String.join(",", (List<String>) value);
boolean valueChanged = !characteristic.getStringValue(0).equals(valueString);
if (valueChanged) {
- Assert.assertTrue(mTbsGatt.setBearerUriSchemesSupportedList((List<String>) value));
+ assertThat(mTbsGatt.setBearerUriSchemesSupportedList((List<String>) value))
+ .isTrue();
} else {
- Assert.assertFalse(mTbsGatt.setBearerUriSchemesSupportedList((List<String>) value));
+ assertThat(mTbsGatt.setBearerUriSchemesSupportedList((List<String>) value))
+ .isFalse();
}
Assert.assertEquals(valueString, characteristic.getStringValue(0));
@@ -213,80 +217,73 @@ public class TbsGattTest {
switch (flagStatePair.first) {
case TbsGatt.STATUS_FLAG_INBAND_RINGTONE_ENABLED:
if (flagStatePair.second) {
- Assert.assertTrue(mTbsGatt.setInbandRingtoneFlag(device));
+ assertThat(mTbsGatt.setInbandRingtoneFlag(device)).isTrue();
} else {
- Assert.assertTrue(mTbsGatt.clearInbandRingtoneFlag(device));
+ assertThat(mTbsGatt.clearInbandRingtoneFlag(device)).isTrue();
}
break;
case TbsGatt.STATUS_FLAG_SILENT_MODE_ENABLED:
if (flagStatePair.second) {
- Assert.assertTrue(mTbsGatt.setSilentModeFlag());
+ assertThat(mTbsGatt.setSilentModeFlag()).isTrue();
} else {
- Assert.assertTrue(mTbsGatt.clearSilentModeFlag());
+ assertThat(mTbsGatt.clearSilentModeFlag()).isTrue();
}
break;
default:
- Assert.assertTrue(false);
+ assertWithMessage("Unexpected flag: " + flagStatePair.first).fail();
}
} else if (characteristic.getUuid().equals(TbsGatt.UUID_CALL_STATE)) {
Pair<Map<Integer, TbsCall>, byte[]> callsExpectedPacketPair =
(Pair<Map<Integer, TbsCall>, byte[]>) value;
- Assert.assertTrue(mTbsGatt.setCallState(callsExpectedPacketPair.first));
- Assert.assertTrue(
- Arrays.equals(callsExpectedPacketPair.second, characteristic.getValue()));
+ assertThat(mTbsGatt.setCallState(callsExpectedPacketPair.first)).isTrue();
+ assertThat(characteristic.getValue()).isEqualTo(callsExpectedPacketPair.second);
} else if (characteristic.getUuid().equals(TbsGatt.UUID_BEARER_LIST_CURRENT_CALLS)) {
Pair<Map<Integer, TbsCall>, byte[]> callsExpectedPacketPair =
(Pair<Map<Integer, TbsCall>, byte[]>) value;
- Assert.assertTrue(mTbsGatt.setBearerListCurrentCalls(callsExpectedPacketPair.first));
- Assert.assertTrue(
- Arrays.equals(callsExpectedPacketPair.second, characteristic.getValue()));
+ assertThat(mTbsGatt.setBearerListCurrentCalls(callsExpectedPacketPair.first)).isTrue();
+ assertThat(characteristic.getValue()).isEqualTo(callsExpectedPacketPair.second);
} else if (characteristic.getUuid().equals(TbsGatt.UUID_TERMINATION_REASON)) {
Pair<Integer, Integer> indexReasonPair = (Pair<Integer, Integer>) value;
- Assert.assertTrue(
- mTbsGatt.setTerminationReason(indexReasonPair.first, indexReasonPair.second));
- Assert.assertTrue(
- Arrays.equals(
- new byte[] {
- (byte) indexReasonPair.first.byteValue(),
- indexReasonPair.second.byteValue()
- },
- characteristic.getValue()));
-
+ assertThat(mTbsGatt.setTerminationReason(indexReasonPair.first, indexReasonPair.second))
+ .isTrue();
+ assertThat(characteristic.getValue())
+ .asList()
+ .containsExactly(
+ indexReasonPair.first.byteValue(), indexReasonPair.second.byteValue())
+ .inOrder();
} else if (characteristic.getUuid().equals(TbsGatt.UUID_INCOMING_CALL)) {
if (value == null) {
- Assert.assertTrue(mTbsGatt.clearIncomingCall());
+ assertThat(mTbsGatt.clearIncomingCall()).isTrue();
Assert.assertEquals(0, characteristic.getValue().length);
} else {
Pair<Integer, String> indexStrPair = (Pair<Integer, String>) value;
- Assert.assertTrue(
- mTbsGatt.setIncomingCall(indexStrPair.first, indexStrPair.second));
- Assert.assertTrue(
- Arrays.equals(
+ assertThat(mTbsGatt.setIncomingCall(indexStrPair.first, indexStrPair.second))
+ .isTrue();
+ assertThat(characteristic.getValue())
+ .isEqualTo(
Bytes.concat(
new byte[] {(byte) indexStrPair.first.byteValue()},
- indexStrPair.second.getBytes(StandardCharsets.UTF_8)),
- characteristic.getValue()));
+ indexStrPair.second.getBytes(StandardCharsets.UTF_8)));
}
} else if (characteristic.getUuid().equals(TbsGatt.UUID_CALL_FRIENDLY_NAME)) {
if (value == null) {
- Assert.assertTrue(mTbsGatt.clearFriendlyName());
+ assertThat(mTbsGatt.clearFriendlyName()).isTrue();
Assert.assertEquals(0, characteristic.getValue().length);
} else {
Pair<Integer, String> indexNamePair = (Pair<Integer, String>) value;
- Assert.assertTrue(
- mTbsGatt.setCallFriendlyName(indexNamePair.first, indexNamePair.second));
- Assert.assertTrue(
- Arrays.equals(
+ assertThat(mTbsGatt.setCallFriendlyName(indexNamePair.first, indexNamePair.second))
+ .isTrue();
+ assertThat(characteristic.getValue())
+ .isEqualTo(
Bytes.concat(
new byte[] {(byte) indexNamePair.first.byteValue()},
- indexNamePair.second.getBytes(StandardCharsets.UTF_8)),
- characteristic.getValue()));
+ indexNamePair.second.getBytes(StandardCharsets.UTF_8)));
}
}
@@ -568,21 +565,17 @@ public class TbsGattTest {
BluetoothGattCharacteristic characteristic =
getCharacteristic(TbsGatt.UUID_CALL_CONTROL_POINT);
- int requestedOpcode = TbsGatt.CALL_CONTROL_POINT_OPCODE_ACCEPT;
- int callIndex = 0x01;
- int result = TbsGatt.CALL_CONTROL_POINT_RESULT_SUCCESS;
+ byte requestedOpcode = TbsGatt.CALL_CONTROL_POINT_OPCODE_ACCEPT;
+ byte callIndex = 0x01;
+ byte result = TbsGatt.CALL_CONTROL_POINT_RESULT_SUCCESS;
// Check with notifications enabled
configureNotifications(mFirstDevice, characteristic, true);
mTbsGatt.setCallControlPointResult(mFirstDevice, requestedOpcode, callIndex, result);
- Assert.assertTrue(
- Arrays.equals(
- characteristic.getValue(),
- new byte[] {
- (byte) (requestedOpcode & 0xff),
- (byte) (callIndex & 0xff),
- (byte) (result & 0xff)
- }));
+ assertThat(characteristic.getValue())
+ .asList()
+ .containsExactly(requestedOpcode, callIndex, result)
+ .inOrder();
verify(mMockGattServer, after(2000))
.notifyCharacteristicChanged(eq(mFirstDevice), eq(characteristic), eq(false));
reset(mMockGattServer);
@@ -592,14 +585,10 @@ public class TbsGattTest {
// Check with notifications disabled
configureNotifications(mFirstDevice, characteristic, false);
mTbsGatt.setCallControlPointResult(mFirstDevice, requestedOpcode, callIndex, result);
- Assert.assertTrue(
- Arrays.equals(
- characteristic.getValue(),
- new byte[] {
- (byte) (requestedOpcode & 0xff),
- (byte) (callIndex & 0xff),
- (byte) (result & 0xff)
- }));
+ assertThat(characteristic.getValue())
+ .asList()
+ .containsExactly(requestedOpcode, callIndex, result)
+ .inOrder();
verify(mMockGattServer, after(2000).times(0))
.notifyCharacteristicChanged(any(), any(), anyBoolean());
}
@@ -1053,14 +1042,14 @@ public class TbsGattTest {
@Test
public void testCharacteristicNotifyOnAuthorization() {
prepareDefaultService();
- Assert.assertNotNull(mGattServiceCaptor.getValue());
+ assertThat(mGattServiceCaptor.getValue()).isNotNull();
BluetoothGattCharacteristic characteristic = getCharacteristic(TbsGatt.UUID_STATUS_FLAGS);
configureNotifications(mFirstDevice, characteristic, true);
configureNotifications(mSecondDevice, characteristic, true);
doReturn(mGattServiceCaptor.getValue()).when(mMockGattServer).getService(any(UUID.class));
- Assert.assertNotNull(mGattServiceCaptor.getValue());
+ assertThat(mGattServiceCaptor.getValue()).isNotNull();
// Leave it as unauthorized yet
doReturn(BluetoothDevice.ACCESS_REJECTED)
@@ -1073,7 +1062,7 @@ public class TbsGattTest {
BluetoothGattCharacteristic characteristic2 = getCharacteristic(TbsGatt.UUID_CALL_STATE);
characteristic2.setValue((byte[]) null);
- Assert.assertNotNull(mGattServiceCaptor.getValue());
+ assertThat(mGattServiceCaptor.getValue()).isNotNull();
// Call it once but expect no notification for the unauthorized device
byte[] valueBytes = new byte[2];
@@ -1087,7 +1076,7 @@ public class TbsGattTest {
doReturn(BluetoothDevice.ACCESS_ALLOWED)
.when(mMockTbsService)
.getDeviceAuthorization(any(BluetoothDevice.class));
- Assert.assertNotNull(mGattServiceCaptor.getValue());
+ assertThat(mGattServiceCaptor.getValue()).isNotNull();
mTbsGatt.onDeviceAuthorizationSet(mFirstDevice);
verify(mMockGattServer, times(0))
.notifyCharacteristicChanged(any(), eq(characteristic2), eq(false));
@@ -1169,7 +1158,7 @@ public class TbsGattTest {
BluetoothGattDescriptor descriptor =
getCharacteristic(TbsGatt.UUID_BEARER_TECHNOLOGY)
.getDescriptor(TbsGatt.UUID_CLIENT_CHARACTERISTIC_CONFIGURATION);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
doReturn(BluetoothDevice.ACCESS_REJECTED)
.when(mMockTbsService)
@@ -1193,7 +1182,7 @@ public class TbsGattTest {
BluetoothGattDescriptor descriptor =
getCharacteristic(TbsGatt.UUID_BEARER_TECHNOLOGY)
.getDescriptor(TbsGatt.UUID_CLIENT_CHARACTERISTIC_CONFIGURATION);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
doReturn(BluetoothDevice.ACCESS_UNKNOWN)
.when(mMockTbsService)
@@ -1211,7 +1200,7 @@ public class TbsGattTest {
BluetoothGattDescriptor descriptor =
getCharacteristic(TbsGatt.UUID_CALL_CONTROL_POINT)
.getDescriptor(TbsGatt.UUID_CLIENT_CHARACTERISTIC_CONFIGURATION);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
doReturn(BluetoothDevice.ACCESS_REJECTED)
.when(mMockTbsService)
@@ -1241,7 +1230,7 @@ public class TbsGattTest {
BluetoothGattDescriptor descriptor =
getCharacteristic(TbsGatt.UUID_CALL_CONTROL_POINT)
.getDescriptor(TbsGatt.UUID_CLIENT_CHARACTERISTIC_CONFIGURATION);
- Assert.assertNotNull(descriptor);
+ assertThat(descriptor).isNotNull();
doReturn(BluetoothDevice.ACCESS_UNKNOWN)
.when(mMockTbsService)
diff --git a/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java
index e568fc7bac..c0f275b149 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.telephony;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@@ -125,13 +127,12 @@ public class BluetoothInCallServiceTest {
boolean callAnswered = mBluetoothInCallService.answerCall();
verify(mockCall).answer(any(int.class));
- Assert.assertTrue(callAnswered);
+ assertThat(callAnswered).isTrue();
}
@Test
public void headsetAnswerCallNull() {
- boolean callAnswered = mBluetoothInCallService.answerCall();
- Assert.assertFalse(callAnswered);
+ assertThat(mBluetoothInCallService.answerCall()).isFalse();
}
@Test
@@ -141,13 +142,12 @@ public class BluetoothInCallServiceTest {
boolean callHungup = mBluetoothInCallService.hangupCall();
verify(mockCall).disconnect();
- Assert.assertTrue(callHungup);
+ assertThat(callHungup).isTrue();
}
@Test
public void headsetHangupCallNull() {
- boolean callHungup = mBluetoothInCallService.hangupCall();
- Assert.assertFalse(callHungup);
+ assertThat(mBluetoothInCallService.hangupCall()).isFalse();
}
@Test
@@ -158,13 +158,12 @@ public class BluetoothInCallServiceTest {
verify(mockCall).playDtmfTone(eq((char) TEST_DTMF_TONE));
verify(mockCall).stopDtmfTone();
- Assert.assertTrue(sentDtmf);
+ assertThat(sentDtmf).isTrue();
}
@Test
public void headsetSendDTMFNull() {
- boolean sentDtmf = mBluetoothInCallService.sendDtmf(TEST_DTMF_TONE);
- Assert.assertFalse(sentDtmf);
+ assertThat(mBluetoothInCallService.sendDtmf(TEST_DTMF_TONE)).isFalse();
}
@Test
@@ -1144,7 +1143,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_RELEASEHELD);
verify(ringingCall).reject(eq(false), nullable(String.class));
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1153,7 +1152,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_RELEASEHELD);
verify(onHoldCall).disconnect();
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1166,7 +1165,7 @@ public class BluetoothInCallServiceTest {
verify(activeCall).disconnect();
verify(ringingCall).answer(any(int.class));
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1179,7 +1178,7 @@ public class BluetoothInCallServiceTest {
verify(activeCall).disconnect();
// BluetoothCall unhold will occur as part of CallsManager auto-unholding
// the background BluetoothCall on its own.
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1189,7 +1188,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
verify(ringingCall).answer(any(int.class));
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1199,7 +1198,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
verify(heldCall).unhold();
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1210,7 +1209,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
verify(activeCall).hold();
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1221,7 +1220,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_ADDHELDTOCONF);
verify(activeCall).mergeConference();
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1237,7 +1236,7 @@ public class BluetoothInCallServiceTest {
boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_ADDHELDTOCONF);
verify(activeCall).conference(conferenceableCall);
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
@Test
@@ -1262,7 +1261,7 @@ public class BluetoothInCallServiceTest {
verify(mMockBluetoothHeadset)
.phoneStateChanged(
eq(1), eq(1), eq(CALL_STATE_IDLE), eq(""), eq(128), nullable(String.class));
- Assert.assertTrue(didProcess);
+ assertThat(didProcess).isTrue();
}
// Testing the CallsManager Listener Functionality on Bluetooth
@@ -1681,8 +1680,8 @@ public class BluetoothInCallServiceTest {
public void clear() {
mBluetoothInCallService.clear();
- Assert.assertNull(mBluetoothInCallService.mBluetoothAdapterReceiver);
- Assert.assertNull(mBluetoothInCallService.mBluetoothHeadset);
+ assertThat(mBluetoothInCallService.mBluetoothAdapterReceiver).isNull();
+ assertThat(mBluetoothInCallService.mBluetoothHeadset).isNull();
}
@Test
@@ -1814,11 +1813,11 @@ public class BluetoothInCallServiceTest {
@Test
public void onDestroy() {
- Assert.assertTrue(mBluetoothInCallService.mOnCreateCalled);
+ assertThat(mBluetoothInCallService.mOnCreateCalled).isTrue();
mBluetoothInCallService.onDestroy();
- Assert.assertFalse(mBluetoothInCallService.mOnCreateCalled);
+ assertThat(mBluetoothInCallService.mOnCreateCalled).isFalse();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java
index 18388e1223..3e912701f6 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java
@@ -27,7 +27,9 @@ import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING;
+import static android.bluetooth.IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID;
import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
+import static android.bluetooth.IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
@@ -40,7 +42,6 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -465,10 +466,9 @@ public class VolumeControlServiceTest {
int volume = 6;
assertThat(mService.getGroupVolume(groupId)).isEqualTo(-1);
- mBinder.setGroupVolume(groupId, volume, mAttributionSource);
+ mService.setGroupVolume(groupId, volume);
- int groupVolume = mBinder.getGroupVolume(groupId, mAttributionSource);
- assertThat(groupVolume).isEqualTo(volume);
+ assertThat(mService.getGroupVolume(groupId)).isEqualTo(volume);
volume = 10;
// Send autonomous volume change.
@@ -485,15 +485,14 @@ public class VolumeControlServiceTest {
int groupId_2 = 2;
int volume_groupId_2 = 20;
- assertThat(mService.getGroupVolume(groupId_1)).isEqualTo(-1);
- assertThat(mService.getGroupVolume(groupId_2)).isEqualTo(-1);
- mBinder.setGroupVolume(groupId_1, volume_groupId_1, mAttributionSource);
-
- mBinder.setGroupVolume(groupId_2, volume_groupId_2, mAttributionSource);
+ assertThat(mService.getGroupVolume(groupId_1)).isEqualTo(VOLUME_CONTROL_UNKNOWN_VOLUME);
+ assertThat(mService.getGroupVolume(groupId_2)).isEqualTo(VOLUME_CONTROL_UNKNOWN_VOLUME);
+ mService.setGroupVolume(groupId_1, volume_groupId_1);
+ mService.setGroupVolume(groupId_2, volume_groupId_2);
// Make device Active now. This will trigger setting volume to AF
when(mLeAudioService.getActiveGroupId()).thenReturn(groupId_1);
- mBinder.setGroupActive(groupId_1, true, mAttributionSource);
+ mService.setGroupActive(groupId_1, true);
// Expected index for STREAM_MUSIC
int expectedVol =
@@ -502,7 +501,7 @@ public class VolumeControlServiceTest {
// Make device Active now. This will trigger setting volume to AF
when(mLeAudioService.getActiveGroupId()).thenReturn(groupId_2);
- mBinder.setGroupActive(groupId_2, true, mAttributionSource);
+ mService.setGroupActive(groupId_2, true);
expectedVol =
(int) Math.round((double) (volume_groupId_2 * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL);
@@ -520,7 +519,7 @@ public class VolumeControlServiceTest {
generateVolumeStateChanged(null, groupId, volume, 0, false, true);
// Mute
- mBinder.muteGroup(groupId, mAttributionSource);
+ mService.muteGroup(groupId);
assertThat(mService.getGroupMute(groupId)).isTrue();
// Make sure the volume is kept even when muted
@@ -545,7 +544,8 @@ public class VolumeControlServiceTest {
// Mute
mService.muteGroup(groupId);
assertThat(mService.getGroupMute(groupId)).isTrue();
- verify(mNativeInterface).muteGroup(eq(groupId));
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface).muteGroup(eq(groupId));
// Make sure the volume is kept even when muted
doReturn(true).when(mAudioManager).isStreamMute(eq(AudioManager.STREAM_MUSIC));
@@ -554,27 +554,28 @@ public class VolumeControlServiceTest {
// Lower the volume and keep it mute
mService.setGroupVolume(groupId, --volume);
assertThat(mService.getGroupMute(groupId)).isTrue();
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
- verify(mNativeInterface, never()).unmuteGroup(eq(groupId));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
+ inOrderNative.verify(mNativeInterface, never()).unmuteGroup(anyInt());
// Don't unmute on consecutive calls either
mService.setGroupVolume(groupId, --volume);
assertThat(mService.getGroupMute(groupId)).isTrue();
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
- verify(mNativeInterface, never()).unmuteGroup(eq(groupId));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
+ inOrderNative.verify(mNativeInterface, never()).unmuteGroup(anyInt());
// Raise the volume and unmute
volume += 10; // avoid previous volume levels and simplify mock verification
doReturn(false).when(mAudioManager).isStreamMute(eq(AudioManager.STREAM_MUSIC));
mService.setGroupVolume(groupId, ++volume);
assertThat(mService.getGroupMute(groupId)).isFalse();
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
+ inOrderNative.verify(mNativeInterface).unmuteGroup(eq(groupId));
// Verify the number of unmute calls after the second volume change
mService.setGroupVolume(groupId, ++volume);
assertThat(mService.getGroupMute(groupId)).isFalse();
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
// Make sure we unmuted only once
- verify(mNativeInterface).unmuteGroup(eq(groupId));
+ inOrderNative.verify(mNativeInterface, never()).unmuteGroup(anyInt());
}
/** Test if phone will set volume which is read from the buds */
@@ -591,6 +592,8 @@ public class VolumeControlServiceTest {
// Both devices are in the same group
when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
+ when(mCsipService.getGroupDevicesOrdered(groupId))
+ .thenReturn(Arrays.asList(mDevice, mDeviceTwo));
generateDeviceAvailableMessageFromNative(mDevice, 1);
generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
@@ -600,15 +603,21 @@ public class VolumeControlServiceTest {
when(mBassClientService.getSyncedBroadcastSinks()).thenReturn(new ArrayList<>());
// Group is not active unicast and not active primary broadcast, AF will not be notified
generateVolumeStateChanged(
- mDevice, groupId, volumeDevice, flags, initialMuteState, initialAutonomousFlag);
- verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ mDevice,
+ LE_AUDIO_GROUP_ID_INVALID,
+ volumeDevice,
+ flags,
+ initialMuteState,
+ initialAutonomousFlag);
+ InOrder inOrderAudio = inOrder(mAudioManager);
+ inOrderAudio.verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
// Make device Active now. This will trigger setting volume to AF
when(mLeAudioService.getActiveGroupId()).thenReturn(groupId);
- mBinder.setGroupActive(groupId, true, mAttributionSource);
+ mService.setGroupActive(groupId, true);
int expectedAfVol =
(int) Math.round((double) (volumeDevice * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL);
- verify(mAudioManager).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt());
+ inOrderAudio.verify(mAudioManager).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt());
// Connect second device and read different volume. Expect it will NOT be set to AF
// and to another set member, but the existing volume gets applied to it
@@ -616,21 +625,16 @@ public class VolumeControlServiceTest {
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
-
- // Group is now active, AF will be notified. Native will take care to sync the volume
generateVolumeStateChanged(
mDeviceTwo,
- groupId,
+ LE_AUDIO_GROUP_ID_INVALID,
volumeDeviceTwo,
flags,
initialMuteState,
initialAutonomousFlag);
- expectedAfVol = volumeDevice;
- int unexpectedAfVol =
- (int) Math.round((double) (volumeDeviceTwo * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL);
- verify(mAudioManager, times(0)).setStreamVolume(anyInt(), eq(unexpectedAfVol), anyInt());
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(expectedAfVol));
+ inOrderAudio.verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volumeDevice));
}
private void testConnectedDeviceWithResetFlag(
@@ -646,6 +650,8 @@ public class VolumeControlServiceTest {
// Both devices are in the same group
when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
+ when(mCsipService.getGroupDevicesOrdered(groupId))
+ .thenReturn(Arrays.asList(mDevice, mDeviceTwo));
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(streamVolume);
when(mAudioManager.getStreamMaxVolume(anyInt())).thenReturn(streamMaxVolume);
@@ -658,41 +664,41 @@ public class VolumeControlServiceTest {
int expectedAfVol =
(int) Math.round((double) streamVolume * BT_LE_AUDIO_MAX_VOL / streamMaxVolume);
- // Group is not active, AF will not be notified
+ // Group is not active, AF will not be notified. Device volume updated to system volume.
generateVolumeStateChanged(
mDevice,
- groupId,
+ LE_AUDIO_GROUP_ID_INVALID,
resetVolumeDeviceOne,
resetFlag,
initialMuteState,
initialAutonomousFlag);
- verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+
+ InOrder inOrderAudio = inOrder(mAudioManager);
+ inOrderAudio.verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(expectedAfVol));
// Make device Active now. This will trigger setting volume to AF
when(mLeAudioService.getActiveGroupId()).thenReturn(groupId);
- mBinder.setGroupActive(groupId, true, mAttributionSource);
-
- verify(mAudioManager).setStreamVolume(anyInt(), eq(streamVolume), anyInt());
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(expectedAfVol));
+ mService.setGroupActive(groupId, true);
+ inOrderAudio.verify(mAudioManager).setStreamVolume(anyInt(), eq(streamVolume), anyInt());
- // Connect second device and read different volume. Expect it will be set to AF and to
- // another set member
+ // Connect second device and read different volume. Expect it will NOT be set to AF
+ // and to another set member, but the existing volume gets applied to it
generateDeviceAvailableMessageFromNative(mDeviceTwo, 1);
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
-
- // Group is now active, AF will be notified. Native will take care to sync the volume
generateVolumeStateChanged(
mDeviceTwo,
- groupId,
+ LE_AUDIO_GROUP_ID_INVALID,
resetVolumeDeviceTwo,
resetFlag,
initialMuteState,
initialAutonomousFlag);
- verify(mAudioManager).setStreamVolume(anyInt(), anyInt(), anyInt());
- verify(mNativeInterface, times(2)).setGroupVolume(eq(groupId), eq(expectedAfVol));
+ inOrderAudio.verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(expectedAfVol));
}
/** Test if phone will set volume which is read from the buds */
@@ -715,6 +721,7 @@ public class VolumeControlServiceTest {
public void lateConnectingDevice() {
int groupId = 1;
int groupVolume = 56;
+ int volume_2 = 20;
// Both devices are in the same group
when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
@@ -725,14 +732,18 @@ public class VolumeControlServiceTest {
assertThat(mService.getDevices()).contains(mDevice);
mService.setGroupVolume(groupId, groupVolume);
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
- verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
+ inOrderNative.verify(mNativeInterface, never()).setVolume(any(), anyInt());
// Verify that second device gets the proper group volume level when connected
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
- verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ generateVolumeStateChanged(mDeviceTwo, LE_AUDIO_GROUP_ID_INVALID, volume_2, 0, false, true);
+
+ inOrderNative.verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
}
/**
@@ -746,7 +757,8 @@ public class VolumeControlServiceTest {
// For now only one device is in the group
when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
- when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(-1);
+ when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP))
+ .thenReturn(CSIS_GROUP_ID_INVALID);
generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED);
@@ -759,12 +771,13 @@ public class VolumeControlServiceTest {
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
- verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface, never()).setVolume(any(), anyInt());
// But gets the volume when it becomes the group member
when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
mService.handleGroupNodeAdded(groupId, mDeviceTwo);
- verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ inOrderNative.verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(groupVolume));
}
/**
@@ -776,6 +789,7 @@ public class VolumeControlServiceTest {
public void muteLateConnectingDevice() {
int groupId = 1;
int volume = 100;
+ int volume_2 = 20;
// Both devices are in the same group
when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
@@ -789,20 +803,23 @@ public class VolumeControlServiceTest {
doReturn(true).when(mAudioManager).isStreamMute(anyInt());
mService.setGroupVolume(groupId, volume);
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
- verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(volume));
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
+ inOrderNative.verify(mNativeInterface, never()).setVolume(any(), anyInt());
// Check if it was muted
- verify(mNativeInterface).muteGroup(eq(groupId));
-
+ inOrderNative.verify(mNativeInterface).muteGroup(eq(groupId));
assertThat(mService.getGroupMute(groupId)).isTrue();
// Verify that second device gets the proper group volume level when connected
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
- verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(volume));
+ generateVolumeStateChanged(mDeviceTwo, LE_AUDIO_GROUP_ID_INVALID, volume_2, 0, false, true);
+
// Check if new device was muted
- verify(mNativeInterface).mute(eq(mDeviceTwo));
+ inOrderNative.verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(volume));
+ inOrderNative.verify(mNativeInterface).mute(eq(mDeviceTwo));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume));
}
/**
@@ -817,7 +834,8 @@ public class VolumeControlServiceTest {
// For now only one device is in the group
when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
- when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(-1);
+ when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP))
+ .thenReturn(CSIS_GROUP_ID_INVALID);
generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED);
@@ -831,15 +849,18 @@ public class VolumeControlServiceTest {
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
- verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(volume));
+ generateVolumeStateChanged(mDeviceTwo, LE_AUDIO_GROUP_ID_INVALID, volume, 0, false, true);
+
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface, never()).setVolume(any(), anyInt());
// Check if it was not muted
- verify(mNativeInterface, never()).mute(eq(mDeviceTwo));
+ inOrderNative.verify(mNativeInterface, never()).mute(any());
// But gets the volume when it becomes the group member
when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
mService.handleGroupNodeAdded(groupId, mDeviceTwo);
- verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(volume));
- verify(mNativeInterface).mute(eq(mDeviceTwo));
+ inOrderNative.verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(volume));
+ inOrderNative.verify(mNativeInterface).mute(eq(mDeviceTwo));
}
@Test
@@ -876,6 +897,72 @@ public class VolumeControlServiceTest {
}
@Test
+ public void getGroupId() {
+ int groupId_1 = 1;
+ int groupId_2 = 2;
+ int groupVolume = 56;
+
+ generateDeviceAvailableMessageFromNative(mDevice, 1);
+ generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
+ assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED);
+ assertThat(mService.getDevices()).contains(mDevice);
+
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP))
+ .thenReturn(LE_AUDIO_GROUP_ID_INVALID);
+ when(mLeAudioService.getGroupId(mDevice)).thenReturn(LE_AUDIO_GROUP_ID_INVALID);
+ mService.setDeviceVolume(mDevice, groupVolume, true);
+ verify(mNativeInterface, never()).setGroupVolume(anyInt(), anyInt());
+
+ when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId_1);
+ mService.setDeviceVolume(mDevice, groupVolume, true);
+ verify(mNativeInterface).setGroupVolume(groupId_1, groupVolume);
+
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId_2);
+ mService.setDeviceVolume(mDevice, groupVolume, true);
+ verify(mNativeInterface).setGroupVolume(groupId_2, groupVolume);
+ }
+
+ @Test
+ public void getGroupDevices() throws Exception {
+ int groupId = 1;
+ int groupVolume = 56;
+
+ // Send a message to trigger connection completed
+ generateDeviceAvailableMessageFromNative(mDevice, 2);
+
+ // Register callback and verify it is called with known devices
+ IBluetoothVolumeControlCallback callback =
+ Mockito.mock(IBluetoothVolumeControlCallback.class);
+ Binder binder = Mockito.mock(Binder.class);
+ when(callback.asBinder()).thenReturn(binder);
+
+ synchronized (mService.mCallbacks) {
+ int size = mService.mCallbacks.getRegisteredCallbackCount();
+ mService.registerCallback(callback);
+ assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1);
+ }
+
+ InOrder inOrderCallback = inOrder(callback);
+
+ generateVolumeStateChanged(null, groupId, groupVolume, 0, false, false);
+ inOrderCallback.verify(callback, never()).onDeviceVolumeChanged(any(), anyInt());
+
+ when(mLeAudioService.getGroupDevices(groupId)).thenReturn(Arrays.asList(mDevice));
+ generateVolumeStateChanged(null, groupId, groupVolume, 0, false, false);
+ inOrderCallback.verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(groupVolume));
+
+ when(mCsipService.getGroupDevicesOrdered(groupId)).thenReturn(Arrays.asList(mDeviceTwo));
+ generateVolumeStateChanged(null, groupId, groupVolume, 0, false, false);
+ inOrderCallback.verify(callback).onDeviceVolumeChanged(eq(mDeviceTwo), eq(groupVolume));
+
+ when(mCsipService.getGroupDevicesOrdered(groupId))
+ .thenReturn(Arrays.asList(mDevice, mDeviceTwo));
+ generateVolumeStateChanged(null, groupId, groupVolume, 0, false, false);
+ inOrderCallback.verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(groupVolume));
+ inOrderCallback.verify(callback).onDeviceVolumeChanged(eq(mDeviceTwo), eq(groupVolume));
+ }
+
+ @Test
public void serviceBinderSetDeviceVolumeMethods() {
int groupId = 1;
int groupVolume = 56;
@@ -883,43 +970,54 @@ public class VolumeControlServiceTest {
int deviceTwoVolume = 36;
// Both devices are in the same group
- when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId);
- when(mLeAudioService.getGroupId(mDeviceTwo)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
generateDeviceAvailableMessageFromNative(mDevice, 1);
generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDevice);
+ InOrder inOrderNative = inOrder(mNativeInterface);
+
mBinder.setDeviceVolume(mDevice, groupVolume, true, mAttributionSource);
- verify(mNativeInterface).setGroupVolume(groupId, groupVolume);
+ inOrderNative.verify(mNativeInterface, never()).setVolume(any(), anyInt());
+ inOrderNative.verify(mNativeInterface).setGroupVolume(groupId, groupVolume);
assertThat(mService.getGroupVolume(groupId)).isEqualTo(groupVolume);
mBinder.setDeviceVolume(mDevice, deviceOneVolume, false, mAttributionSource);
- verify(mNativeInterface).setVolume(mDevice, deviceOneVolume);
+ inOrderNative.verify(mNativeInterface).setVolume(mDevice, deviceOneVolume);
assertThat(mService.getDeviceVolume(mDevice)).isEqualTo(deviceOneVolume);
Assert.assertNotEquals(deviceOneVolume, mService.getDeviceVolume(mDeviceTwo));
+ inOrderNative.verify(mNativeInterface, never()).setGroupVolume(anyInt(), anyInt());
mBinder.setDeviceVolume(mDeviceTwo, deviceTwoVolume, false, mAttributionSource);
- verify(mNativeInterface).setVolume(mDeviceTwo, deviceTwoVolume);
+ inOrderNative.verify(mNativeInterface).setVolume(mDeviceTwo, deviceTwoVolume);
assertThat(mService.getDeviceVolume(mDeviceTwo)).isEqualTo(deviceTwoVolume);
Assert.assertNotEquals(deviceTwoVolume, mService.getDeviceVolume(mDevice));
+ inOrderNative.verify(mNativeInterface, never()).setGroupVolume(anyInt(), anyInt());
}
@Test
@EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_VOLUME_CONTROL_FOR_CONNECTED_DEVICES)
public void testServiceBinderSetDeviceVolumeNoGroupId() throws Exception {
int deviceVolume = 42;
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP))
+ .thenReturn(LE_AUDIO_GROUP_ID_INVALID);
when(mLeAudioService.getGroupId(mDevice)).thenReturn(LE_AUDIO_GROUP_ID_INVALID);
generateDeviceAvailableMessageFromNative(mDevice, 1);
- generateConnectionMessageFromNative(
- mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
+ generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getDevices()).contains(mDevice);
+ mBinder.setDeviceVolume(mDevice, deviceVolume, true, mAttributionSource);
+ verify(mNativeInterface, never()).setVolume(any(), anyInt());
+ verify(mNativeInterface, never()).setGroupVolume(anyInt(), anyInt());
+
mBinder.setDeviceVolume(mDevice, deviceVolume, false, mAttributionSource);
verify(mNativeInterface).setVolume(mDevice, deviceVolume);
assertThat(mService.getDeviceVolume(mDevice)).isEqualTo(deviceVolume);
+ verify(mNativeInterface, never()).setGroupVolume(anyInt(), anyInt());
}
@Test
@@ -954,15 +1052,20 @@ public class VolumeControlServiceTest {
assertThat(mService.getDevices()).contains(mDevice);
mService.setGroupVolume(groupId, groupVolume);
- verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
- verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ InOrder inOrderNative = inOrder(mNativeInterface);
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
+ inOrderNative.verify(mNativeInterface, never()).setVolume(any(), anyInt());
// Verify that second device gets the proper group volume level when connected
generateDeviceAvailableMessageFromNative(mDeviceTwo, 1);
generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED);
assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDeviceTwo);
- verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ generateVolumeStateChanged(
+ mDeviceTwo, LE_AUDIO_GROUP_ID_INVALID, groupVolume, 0, false, true);
+
+ inOrderNative.verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(groupVolume));
+ inOrderNative.verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
// Generate events for both devices
generateDeviceOffsetChangedMessageFromNative(mDevice, 1, 100);
@@ -1042,8 +1145,8 @@ public class VolumeControlServiceTest {
verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(deviceTwoVolume));
// Both devices are in the same group
- when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId);
- when(mLeAudioService.getGroupId(mDeviceTwo)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
// Register callback and verify it is called with known devices
IBluetoothVolumeControlCallback callback =
@@ -1083,8 +1186,8 @@ public class VolumeControlServiceTest {
verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(deviceTwoVolume));
// Both devices are in the same group
- when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId);
- when(mLeAudioService.getGroupId(mDeviceTwo)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
// Register callback and verify it is called with known devices
IBluetoothVolumeControlCallback callback =
@@ -1150,13 +1253,13 @@ public class VolumeControlServiceTest {
int deviceOneVolume = 46;
// Both devices are in the same group
- when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId);
- when(mLeAudioService.getGroupId(mDeviceTwo)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId);
+ when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId);
// Send a message to trigger connection completed
generateDeviceAvailableMessageFromNative(mDevice, 2);
- mBinder.setDeviceVolume(mDevice, groupVolume, true, mAttributionSource);
+ mService.setDeviceVolume(mDevice, groupVolume, true);
verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume));
// Register callback and verify it is called with known devices
@@ -1171,7 +1274,7 @@ public class VolumeControlServiceTest {
assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1);
}
- when(mLeAudioService.getGroupDevices(groupId))
+ when(mCsipService.getGroupDevicesOrdered(groupId))
.thenReturn(Arrays.asList(mDevice, mDeviceTwo));
// Send group volume change.
@@ -1181,7 +1284,8 @@ public class VolumeControlServiceTest {
verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(groupVolume));
// Send device volume change only for one device
- generateVolumeStateChanged(mDevice, -1, deviceOneVolume, 0, false, false);
+ generateVolumeStateChanged(
+ mDevice, LE_AUDIO_GROUP_ID_INVALID, deviceOneVolume, 0, false, false);
verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(deviceOneVolume));
verify(callback, never()).onDeviceVolumeChanged(eq(mDeviceTwo), eq(deviceOneVolume));
@@ -1205,25 +1309,23 @@ public class VolumeControlServiceTest {
assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED);
assertThat(mService.getDevices()).contains(mDevice);
- // Make active group as null and broadcast active
+ // Make active group as null and broadcast not active
when(mLeAudioService.getActiveGroupId()).thenReturn(LE_AUDIO_GROUP_ID_INVALID);
when(mBassClientService.getSyncedBroadcastSinks()).thenReturn(new ArrayList<>());
- // Group is broadcast primary group, AF will not be notified
+ // Group is not broadcast primary group, AF will not be notified
generateVolumeStateChanged(null, groupId, groupVolume, 0, false, true);
- verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ InOrder inOrderAudio = inOrder(mAudioManager);
+ inOrderAudio.verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
// Make active group as null and broadcast active
when(mLeAudioService.getActiveGroupId()).thenReturn(LE_AUDIO_GROUP_ID_INVALID);
when(mBassClientService.getSyncedBroadcastSinks())
.thenReturn(Arrays.asList(mDevice, mDeviceTwo));
- when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId);
- when(mLeAudioService.getGroupId(mDeviceTwo)).thenReturn(groupId);
when(mLeAudioService.isPrimaryGroup(groupId)).thenReturn(true);
- // Group is not broadcast primary group, AF will not be notified
+ // Group is broadcast primary group, AF will be notified
generateVolumeStateChanged(null, groupId, groupVolume, 0, false, true);
-
- verify(mAudioManager).setStreamVolume(anyInt(), anyInt(), anyInt());
+ inOrderAudio.verify(mAudioManager).setStreamVolume(anyInt(), anyInt(), anyInt());
}
private void generateConnectionMessageFromNative(
diff --git a/android/pandora/gen_cov.py b/android/pandora/gen_cov.py
index 85ed6c6a6d..b3d85b32d6 100755
--- a/android/pandora/gen_cov.py
+++ b/android/pandora/gen_cov.py
@@ -9,8 +9,8 @@ import subprocess
import sys
import xml.etree.ElementTree as ET
-JAVA_UNIT_TESTS = 'test/mts/tools/mts-tradefed/res/config/mts-bluetooth-tests-list-shard-01.xml'
-NATIVE_UNIT_TESTS = 'test/mts/tools/mts-tradefed/res/config/mts-bluetooth-tests-list-shard-02.xml'
+JAVA_UNIT_TESTS = 'test/mts/tools/mts-tradefed/res/config/mts-bt-tests-list-shard-01.xml'
+NATIVE_UNIT_TESTS = 'test/mts/tools/mts-tradefed/res/config/mts-bt-tests-list-shard-02.xml'
DO_NOT_RETRY_TESTS = {
'CtsBluetoothTestCases',
'GoogleBluetoothInstrumentationTests',
diff --git a/android/pandora/server/Android.bp b/android/pandora/server/Android.bp
index 52e9e405a9..83cb971cd3 100644
--- a/android/pandora/server/Android.bp
+++ b/android/pandora/server/Android.bp
@@ -77,6 +77,9 @@ android_test {
"configs/pts_bot_tests_config.json",
"configs/pts_bot_tests_config_auto.json",
],
- test_suites: ["mts-bluetooth"],
+ test_suites: [
+ "mts-bluetooth",
+ "mts-bt",
+ ],
min_sdk_version: "Tiramisu",
}
diff --git a/android/pandora/server/configs/pts_bot_tests_config.json b/android/pandora/server/configs/pts_bot_tests_config.json
index 6ebae93244..758d21f07c 100644
--- a/android/pandora/server/configs/pts_bot_tests_config.json
+++ b/android/pandora/server/configs/pts_bot_tests_config.json
@@ -3216,15 +3216,6 @@
"flags": [
{
"flags": [
- "avdtp_error_codes"
- ],
- "tests": [
- "A2DP/SNK/AVP",
- "A2DP/SRC/AVP"
- ]
- },
- {
- "flags": [
"leaudio_allow_leaudio_only_devices",
"enable_hap_by_default"
],
diff --git a/android/pandora/server/src/Pbap.kt b/android/pandora/server/src/Pbap.kt
index 5b7cef45ad..e8eab8bf1c 100644
--- a/android/pandora/server/src/Pbap.kt
+++ b/android/pandora/server/src/Pbap.kt
@@ -159,8 +159,6 @@ class Pbap(val context: Context) : PBAPImplBase(), Closeable {
"""
%d Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vivamus condimentum rhoncus est volutpat venenatis.
- Fusce semper, sapien ut venenatis pellentesque,
- lorem dui aliquam sapien, non pharetra diam neque id mi.
"""
}
}
diff --git a/android/pandora/test/a2dp/__init__.py b/android/pandora/test/a2dp/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/android/pandora/test/a2dp/__init__.py
diff --git a/android/pandora/test/a2dp/packets/__init__.py b/android/pandora/test/a2dp/packets/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/android/pandora/test/a2dp/packets/__init__.py
diff --git a/android/pandora/test/a2dp/packets/avdtp.pdl b/android/pandora/test/a2dp/packets/avdtp.pdl
new file mode 100644
index 0000000000..ff9fc849dc
--- /dev/null
+++ b/android/pandora/test/a2dp/packets/avdtp.pdl
@@ -0,0 +1,343 @@
+little_endian_packets
+
+enum PacketType : 2 {
+ SINGLE_PACKET = 0,
+ START_PACKET = 1,
+ CONTINUE_PACKET = 2,
+ END_PACKET = 3,
+}
+
+enum MessageType : 2 {
+ COMMAND = 0,
+ GENERAL_REJECT = 1,
+ RESPONSE_ACCEPT = 2,
+ RESPONSE_REJECT = 3,
+}
+
+enum SignalIdentifier : 6 {
+ AVDTP_DISCOVER = 0x01,
+ AVDTP_GET_CAPABILITIES = 0x02,
+ AVDTP_SET_CONFIGURATION = 0x03,
+ AVDTP_GET_CONFIGURATION = 0x04,
+ AVDTP_RECONFIGURE = 0x05,
+ AVDTP_OPEN = 0x06,
+ AVDTP_START = 0x07,
+ AVDTP_CLOSE = 0x08,
+ AVDTP_SUSPEND = 0x09,
+ AVDTP_ABORT = 0x0A,
+ AVDTP_SECURITY_CONTROL = 0x0B,
+ AVDTP_GET_ALL_CAPABILITIES = 0x0C,
+ AVDTP_DELAYREPORT = 0x0D,
+}
+
+enum ErrorCode : 8 {
+ SUCCESS = 0,
+
+ // [AVDTP_1.3] 8.20.6.2 ERROR_CODE tables.
+ AVDTP_BAD_HEADER_FORMAT = 0x01,
+ AVDTP_BAD_LENGTH = 0x11,
+ AVDTP_BAD_ACP_SEID = 0x12,
+ AVDTP_SEP_IN_USE = 0x13,
+ AVDTP_SEP_NOT_IN_USE = 0x14,
+ AVDTP_BAD_SERV_CATEGORY = 0x17,
+ AVDTP_BAD_PAYLOAD_FORMAT = 0x18,
+ AVDTP_NOT_SUPPORTED_COMMAND = 0x19,
+ AVDTP_INVALID_CAPABILITIES = 0x1A,
+ AVDTP_BAD_RECOVERY_TYPE = 0x22,
+ AVDTP_BAD_MEDIA_TRANSPORT_FORMAT = 0x23,
+ AVDTP_BAD_RECOVERY_FORMAT = 0x25,
+ AVDTP_BAD_ROHC_FORMAT = 0x26,
+ AVDTP_BAD_CP_FORMAT = 0x27,
+ AVDTP_BAD_MULTIPLEXING_FORMAT = 0x28,
+ AVDTP_UNSUPPORTED_CONFIGURATION = 0x29,
+ AVDTP_BAD_STATE = 0x31,
+
+ // [GAVDTP_1.3] 3.3 Error codes.
+ GAVDTP_BAD_SERVICE = 0x80,
+ GAVDTP_INSUFFICIENT_RESOURCES = 0x81,
+
+ // [A2DP_1.3.2] 5.1.3 Error Codes.
+ A2DP_INVALID_CODEC_TYPE = 0xC1,
+ A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xC2,
+ A2DP_INVALID_SAMPLING_FREQUENCY = 0xC3,
+ A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xC4,
+ A2DP_INVALID_CHANNEL_MODE = 0xC5,
+ A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xC6,
+ A2DP_INVALID_SUBBANDS = 0xC7,
+ A2DP_NOT_SUPPORTED_SUBBANDS = 0xC8,
+ A2DP_INVALID_ALLOCATION_METHOD = 0xC9,
+ A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xCA,
+ A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xCB,
+ A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xCC,
+ A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xCD,
+ A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xCE,
+ A2DP_INVALID_LAYER = 0xCF,
+ A2DP_NOT_SUPPORTED_LAYER = 0xD0,
+ A2DP_NOT_SUPPORTED_CRC = 0xD1,
+ A2DP_NOT_SUPPORTED_MPF = 0xD2,
+ A2DP_NOT_SUPPORTED_VBR = 0xD3,
+ A2DP_INVALID_BIT_RATE = 0xD4,
+ A2DP_NOT_SUPPORTED_BIT_RATE = 0xD5,
+ A2DP_INVALID_OBJECT_TYPE = 0xD6,
+ A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xD7,
+ A2DP_INVALID_CHANNELS = 0xD8,
+ A2DP_NOT_SUPPORTED_CHANNELS = 0xD9,
+ A2DP_INVALID_BLOCK_LENGTH = 0xDD,
+ A2DP_INVALID_CP_TYPE = 0xE0,
+ A2DP_INVALID_CP_FORMAT = 0xE1,
+ A2DP_INVALID_CODEC_PARAMETER = 0xE2,
+ A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xE3,
+}
+
+enum Tsep : 1 {
+ SOURCE = 0,
+ SINK = 1,
+}
+
+enum ServiceCategory : 8 {
+ MEDIA_TRANSPORT = 0x1,
+ REPORTING = 0x2,
+ RECOVERY = 0x3,
+ CONTENT_PROTECTION = 0x4,
+ HEADER_COMPRESSION = 0x5,
+ MULTIPLEXING = 0x6,
+ MEDIA_CODEC = 0x7,
+ DELAY_REPORTING = 0x8,
+}
+
+struct SeidInformation {
+ _reserved_ : 1,
+ in_use : 1,
+ acp_seid : 6,
+ _reserved_ : 3,
+ tsep : Tsep,
+ media_type : 4,
+}
+
+struct ServiceCapability {
+ service_category : ServiceCategory,
+ _size_ (_payload_) : 8,
+ _payload_,
+}
+
+struct MediaTransportCapability : ServiceCapability (service_category = MEDIA_TRANSPORT) {
+}
+
+struct ReportingCapability : ServiceCapability (service_category = REPORTING) {
+}
+
+struct RecoveryCapability : ServiceCapability (service_category = RECOVERY) {
+ recovery_type : 8,
+ maximum_recovery_window_size : 8,
+ maximum_number_of_media_packets_in_parity_code : 8,
+}
+
+struct ContentProtectionCapability : ServiceCapability (service_category = CONTENT_PROTECTION) {
+ cp_type : 16, // Little endian
+ _payload_,
+}
+
+struct HeaderCompressionCapability : ServiceCapability (service_category = HEADER_COMPRESSION) {
+ _reserved_ : 5,
+ recovery : 1,
+ media : 1,
+ back_ch : 1,
+}
+
+struct MultiplexingCapability : ServiceCapability (service_category = MULTIPLEXING) {
+ _reserved_ : 7,
+ frag : 1,
+ _payload_,
+}
+
+struct MediaCodecCapability : ServiceCapability (service_category = MEDIA_CODEC) {
+ _reserved_ : 4,
+ media_type : 4,
+ media_codec_type : 8,
+ media_codec_specific_information_elements : 8[],
+}
+
+struct DelayReportingCapability : ServiceCapability (service_category = DELAY_REPORTING) {
+}
+
+packet SignalingPacket {
+ message_type : MessageType,
+ packet_type : PacketType,
+ transaction_label : 4,
+ signal_identifier : SignalIdentifier,
+ _reserved_ : 2,
+ _payload_,
+}
+
+packet DiscoverCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_DISCOVER) {
+}
+
+packet DiscoverResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_DISCOVER) {
+ seid_information : SeidInformation[]
+}
+
+packet DiscoverReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_DISCOVER) {
+ error_code : ErrorCode,
+}
+
+packet GetCapabilitiesCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_GET_CAPABILITIES) {
+ _reserved_ : 2,
+ acp_seid : 6,
+}
+
+packet GetCapabilitiesResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_GET_CAPABILITIES) {
+ service_capabilities: ServiceCapability[],
+}
+
+packet GetCapabilitiesReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_GET_CAPABILITIES) {
+ error_code: ErrorCode,
+}
+
+packet GetAllCapabilitiesCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_GET_ALL_CAPABILITIES) {
+ _reserved_ : 2,
+ acp_seid : 6,
+}
+
+packet GetAllCapabilitiesResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_GET_ALL_CAPABILITIES) {
+ service_capabilities: ServiceCapability[],
+}
+
+packet GetAllCapabilitiesReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_GET_ALL_CAPABILITIES) {
+ error_code: ErrorCode,
+}
+
+packet SetConfigurationCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_SET_CONFIGURATION) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ _reserved_ : 2,
+ int_seid : 6,
+ service_capabilities: ServiceCapability[],
+}
+
+packet SetConfigurationResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_SET_CONFIGURATION) {
+}
+
+packet SetConfigurationReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_SET_CONFIGURATION) {
+ service_category: 8,
+ error_code: ErrorCode,
+}
+
+packet GetConfigurationCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_GET_CONFIGURATION) {
+ _reserved_ : 2,
+ acp_seid : 6,
+}
+
+packet GetConfigurationResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_GET_CONFIGURATION) {
+ service_capabilities: ServiceCapability[],
+}
+
+packet GetConfigurationReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_GET_CONFIGURATION) {
+ error_code: ErrorCode,
+}
+
+packet ReconfigureCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_RECONFIGURE) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ service_capabilities: ServiceCapability[],
+}
+
+packet ReconfigureResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_RECONFIGURE) {
+}
+
+packet ReconfigureReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_RECONFIGURE) {
+ service_category: 8,
+ error_code: ErrorCode,
+}
+
+packet OpenCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_OPEN) {
+ _reserved_ : 2,
+ acp_seid : 6,
+}
+
+packet OpenResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_OPEN) {
+}
+
+packet OpenReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_OPEN) {
+ error_code: ErrorCode,
+}
+
+packet StartCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_START) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ // acp_seids: 8[],
+}
+
+packet StartResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_START) {
+}
+
+packet StartReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_START) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ error_code: ErrorCode,
+}
+
+packet CloseCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_CLOSE) {
+ _reserved_ : 2,
+ acp_seid: 6,
+}
+
+packet CloseResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_CLOSE) {
+}
+
+packet CloseReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_CLOSE) {
+ error_code: ErrorCode,
+}
+
+packet SuspendCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_SUSPEND) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ // acp_seids: 8[],
+}
+
+packet SuspendResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_SUSPEND) {
+}
+
+packet SuspendReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_SUSPEND) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ error_code: ErrorCode,
+}
+
+packet AbortCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_ABORT) {
+ _reserved_ : 2,
+ acp_seid : 6,
+}
+
+packet AbortResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_ABORT) {
+}
+
+packet SecurityControlCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_SECURITY_CONTROL) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ content_protection_data: 8[],
+}
+
+packet SecurityControlResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_SECURITY_CONTROL) {
+ content_protection_data: 8[],
+}
+
+packet SecurityControlReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_SECURITY_CONTROL) {
+ error_code: ErrorCode,
+}
+
+packet GeneralReject : SignalingPacket (message_type = GENERAL_REJECT) {
+}
+
+packet DelayReportCommand : SignalingPacket (message_type = COMMAND, signal_identifier = AVDTP_DELAYREPORT) {
+ _reserved_ : 2,
+ acp_seid : 6,
+ delay_msb: 8,
+ delay_lsb: 8,
+}
+
+packet DelayReportResponse : SignalingPacket (message_type = RESPONSE_ACCEPT, signal_identifier = AVDTP_DELAYREPORT) {
+}
+
+packet DelayReportReject : SignalingPacket (message_type = RESPONSE_REJECT, signal_identifier = AVDTP_DELAYREPORT) {
+ error_code: ErrorCode,
+}
diff --git a/android/pandora/test/a2dp/packets/avdtp.py b/android/pandora/test/a2dp/packets/avdtp.py
new file mode 100644
index 0000000000..15f9e29d27
--- /dev/null
+++ b/android/pandora/test/a2dp/packets/avdtp.py
@@ -0,0 +1,2109 @@
+# File generated from avdtp_packets.pdl with the command:
+# pdlc avdtp_packets.pdl | pdl-compiler/scripts/generate_python_backend.py
+# /!\ Do not edit by hand.
+from dataclasses import dataclass, field, fields
+from typing import Optional, List, Tuple, Union
+import enum
+import inspect
+import math
+
+
+@dataclass
+class Packet:
+ payload: Optional[bytes] = field(repr=False, default_factory=bytes, compare=False)
+
+ @classmethod
+ def parse_all(cls, span: bytes) -> "Packet":
+ packet, remain = getattr(cls, "parse")(span)
+ if len(remain) > 0:
+ raise Exception("Unexpected parsing remainder")
+ return packet
+
+ @property
+ def size(self) -> int:
+ pass
+
+ def show(self, prefix: str = ""):
+ print(f"{self.__class__.__name__}")
+
+ def print_val(p: str, pp: str, name: str, align: int, typ, val):
+ if name == "payload":
+ pass
+
+ # Scalar fields.
+ elif typ is int:
+ print(f"{p}{name:{align}} = {val} (0x{val:x})")
+
+ # Byte fields.
+ elif typ is bytes:
+ print(f"{p}{name:{align}} = [", end="")
+ line = ""
+ n_pp = ""
+ for idx, b in enumerate(val):
+ if idx > 0 and idx % 8 == 0:
+ print(f"{n_pp}{line}")
+ line = ""
+ n_pp = pp + (" " * (align + 4))
+ line += f" {b:02x}"
+ print(f"{n_pp}{line} ]")
+
+ # Enum fields.
+ elif inspect.isclass(typ) and issubclass(typ, enum.IntEnum):
+ print(f"{p}{name:{align}} = {typ.__name__}::{val.name} (0x{val:x})")
+
+ # Struct fields.
+ elif inspect.isclass(typ) and issubclass(typ, globals().get("Packet")):
+ print(f"{p}{name:{align}} = ", end="")
+ val.show(prefix=pp)
+
+ # Array fields.
+ elif getattr(typ, "__origin__", None) == list:
+ print(f"{p}{name:{align}}")
+ last = len(val) - 1
+ align = 5
+ for idx, elt in enumerate(val):
+ n_p = pp + ("├── " if idx != last else "└── ")
+ n_pp = pp + ("│ " if idx != last else " ")
+ print_val(n_p, n_pp, f"[{idx}]", align, typ.__args__[0], val[idx])
+
+ # Custom fields.
+ elif inspect.isclass(typ):
+ print(f"{p}{name:{align}} = {repr(val)}")
+
+ else:
+ print(f"{p}{name:{align}} = ##{typ}##")
+
+ last = len(fields(self)) - 1
+ align = max(len(f.name) for f in fields(self) if f.name != "payload")
+
+ for idx, f in enumerate(fields(self)):
+ p = prefix + ("├── " if idx != last else "└── ")
+ pp = prefix + ("│ " if idx != last else " ")
+ val = getattr(self, f.name)
+
+ print_val(p, pp, f.name, align, f.type, val)
+
+
+class PacketType(enum.IntEnum):
+ SINGLE_PACKET = 0x0
+ START_PACKET = 0x1
+ CONTINUE_PACKET = 0x2
+ END_PACKET = 0x3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, "PacketType"]:
+ try:
+ return PacketType(v)
+ except ValueError as exn:
+ raise exn
+
+
+class MessageType(enum.IntEnum):
+ COMMAND = 0x0
+ GENERAL_REJECT = 0x1
+ RESPONSE_ACCEPT = 0x2
+ RESPONSE_REJECT = 0x3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, "MessageType"]:
+ try:
+ return MessageType(v)
+ except ValueError as exn:
+ raise exn
+
+
+class SignalIdentifier(enum.IntEnum):
+ AVDTP_DISCOVER = 0x1
+ AVDTP_GET_CAPABILITIES = 0x2
+ AVDTP_SET_CONFIGURATION = 0x3
+ AVDTP_GET_CONFIGURATION = 0x4
+ AVDTP_RECONFIGURE = 0x5
+ AVDTP_OPEN = 0x6
+ AVDTP_START = 0x7
+ AVDTP_CLOSE = 0x8
+ AVDTP_SUSPEND = 0x9
+ AVDTP_ABORT = 0xA
+ AVDTP_SECURITY_CONTROL = 0xB
+ AVDTP_GET_ALL_CAPABILITIES = 0xC
+ AVDTP_DELAYREPORT = 0xD
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, "SignalIdentifier"]:
+ try:
+ return SignalIdentifier(v)
+ except ValueError as exn:
+ raise exn
+
+
+class ErrorCode(enum.IntEnum):
+ SUCCESS = 0x0
+ AVDTP_BAD_HEADER_FORMAT = 0x1
+ AVDTP_BAD_LENGTH = 0x11
+ AVDTP_BAD_ACP_SEID = 0x12
+ AVDTP_SEP_IN_USE = 0x13
+ AVDTP_SEP_NOT_IN_USE = 0x14
+ AVDTP_BAD_SERV_CATEGORY = 0x17
+ AVDTP_BAD_PAYLOAD_FORMAT = 0x18
+ AVDTP_NOT_SUPPORTED_COMMAND = 0x19
+ AVDTP_INVALID_CAPABILITIES = 0x1A
+ AVDTP_BAD_RECOVERY_TYPE = 0x22
+ AVDTP_BAD_MEDIA_TRANSPORT_FORMAT = 0x23
+ AVDTP_BAD_RECOVERY_FORMAT = 0x25
+ AVDTP_BAD_ROHC_FORMAT = 0x26
+ AVDTP_BAD_CP_FORMAT = 0x27
+ AVDTP_BAD_MULTIPLEXING_FORMAT = 0x28
+ AVDTP_UNSUPPORTED_CONFIGURATION = 0x29
+ AVDTP_BAD_STATE = 0x31
+ GAVDTP_BAD_SERVICE = 0x80
+ GAVDTP_INSUFFICIENT_RESOURCES = 0x81
+ A2DP_INVALID_CODEC_TYPE = 0xC1
+ A2DP_NOT_SUPPORTED_CODEC_TYPE = 0xC2
+ A2DP_INVALID_SAMPLING_FREQUENCY = 0xC3
+ A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xC4
+ A2DP_INVALID_CHANNEL_MODE = 0xC5
+ A2DP_NOT_SUPPORTED_CHANNEL_MODE = 0xC6
+ A2DP_INVALID_SUBBANDS = 0xC7
+ A2DP_NOT_SUPPORTED_SUBBANDS = 0xC8
+ A2DP_INVALID_ALLOCATION_METHOD = 0xC9
+ A2DP_NOT_SUPPORTED_ALLOCATION_METHOD = 0xCA
+ A2DP_INVALID_MINIMUM_BITPOOL_VALUE = 0xCB
+ A2DP_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xCC
+ A2DP_INVALID_MAXIMUM_BITPOOL_VALUE = 0xCD
+ A2DP_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xCE
+ A2DP_INVALID_LAYER = 0xCF
+ A2DP_NOT_SUPPORTED_LAYER = 0xD0
+ A2DP_NOT_SUPPORTED_CRC = 0xD1
+ A2DP_NOT_SUPPORTED_MPF = 0xD2
+ A2DP_NOT_SUPPORTED_VBR = 0xD3
+ A2DP_INVALID_BIT_RATE = 0xD4
+ A2DP_NOT_SUPPORTED_BIT_RATE = 0xD5
+ A2DP_INVALID_OBJECT_TYPE = 0xD6
+ A2DP_NOT_SUPPORTED_OBJECT_TYPE = 0xD7
+ A2DP_INVALID_CHANNELS = 0xD8
+ A2DP_NOT_SUPPORTED_CHANNELS = 0xD9
+ A2DP_INVALID_BLOCK_LENGTH = 0xDD
+ A2DP_INVALID_CP_TYPE = 0xE0
+ A2DP_INVALID_CP_FORMAT = 0xE1
+ A2DP_INVALID_CODEC_PARAMETER = 0xE2
+ A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xE3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, "ErrorCode"]:
+ try:
+ return ErrorCode(v)
+ except ValueError as exn:
+ raise exn
+
+
+class Tsep(enum.IntEnum):
+ SOURCE = 0x0
+ SINK = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, "Tsep"]:
+ try:
+ return Tsep(v)
+ except ValueError as exn:
+ raise exn
+
+
+class ServiceCategory(enum.IntEnum):
+ MEDIA_TRANSPORT = 0x1
+ REPORTING = 0x2
+ RECOVERY = 0x3
+ CONTENT_PROTECTION = 0x4
+ HEADER_COMPRESSION = 0x5
+ MULTIPLEXING = 0x6
+ MEDIA_CODEC = 0x7
+ DELAY_REPORTING = 0x8
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, "ServiceCategory"]:
+ try:
+ return ServiceCategory(v)
+ except ValueError as exn:
+ raise exn
+
+
+@dataclass
+class SeidInformation(Packet):
+ in_use: int = field(kw_only=True, default=0)
+ acp_seid: int = field(kw_only=True, default=0)
+ tsep: Tsep = field(kw_only=True, default=Tsep.SOURCE)
+ media_type: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ pass
+
+ @staticmethod
+ def parse(span: bytes) -> Tuple["SeidInformation", bytes]:
+ fields = {"payload": None}
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["in_use"] = (span[0] >> 1) & 0x1
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ fields["tsep"] = Tsep.from_int((span[1] >> 3) & 0x1)
+ fields["media_type"] = (span[1] >> 4) & 0xF
+ span = span[2:]
+ return SeidInformation(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.in_use > 1:
+ print(f"Invalid value for field SeidInformation::in_use: {self.in_use} > 1; the value will be truncated")
+ self.in_use &= 1
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field SeidInformation::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _value = (self.in_use << 1) | (self.acp_seid << 2)
+ _span.append(_value)
+ if self.media_type > 15:
+ print(
+ f"Invalid value for field SeidInformation::media_type: {self.media_type} > 15; the value will be truncated"
+ )
+ self.media_type &= 15
+ _value = (self.tsep << 3) | (self.media_type << 4)
+ _span.append(_value)
+ return bytes(_span)
+
+ @property
+ def size(self) -> int:
+ return 2
+
+
+@dataclass
+class ServiceCapability(Packet):
+ service_category: ServiceCategory = field(kw_only=True, default=ServiceCategory.MEDIA_TRANSPORT)
+
+ def __post_init__(self):
+ pass
+
+ @staticmethod
+ def parse(span: bytes) -> Tuple["ServiceCapability", bytes]:
+ fields = {"payload": None}
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["service_category"] = ServiceCategory.from_int(span[0])
+ _payload__size = span[1]
+ span = span[2:]
+ if len(span) < _payload__size:
+ raise Exception("Invalid packet size")
+ payload = span[:_payload__size]
+ span = span[_payload__size:]
+ fields["payload"] = payload
+ try:
+ child, remain = MediaTransportCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = ReportingCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = RecoveryCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = ContentProtectionCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = HeaderCompressionCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = MultiplexingCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = MediaCodecCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = DelayReportingCapability.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ return ServiceCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.service_category << 0))
+ _payload_size = len(payload or self.payload or [])
+ if _payload_size > 255:
+ print(f"Invalid length for payload field: {_payload_size} > 255; the packet cannot be generated")
+ raise Exception("Invalid payload length")
+ _span.append((_payload_size << 0))
+ _span.extend(payload or self.payload or [])
+ return bytes(_span)
+
+ @property
+ def size(self) -> int:
+ return len(self.payload) + 2
+
+
+@dataclass
+class MediaTransportCapability(ServiceCapability):
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.MEDIA_TRANSPORT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["MediaTransportCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.MEDIA_TRANSPORT:
+ raise Exception("Invalid constraint field values")
+ return MediaTransportCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class ReportingCapability(ServiceCapability):
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.REPORTING
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["ReportingCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.REPORTING:
+ raise Exception("Invalid constraint field values")
+ return ReportingCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class RecoveryCapability(ServiceCapability):
+ recovery_type: int = field(kw_only=True, default=0)
+ maximum_recovery_window_size: int = field(kw_only=True, default=0)
+ maximum_number_of_media_packets_in_parity_code: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.RECOVERY
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["RecoveryCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.RECOVERY:
+ raise Exception("Invalid constraint field values")
+ if len(span) < 3:
+ raise Exception("Invalid packet size")
+ fields["recovery_type"] = span[0]
+ fields["maximum_recovery_window_size"] = span[1]
+ fields["maximum_number_of_media_packets_in_parity_code"] = span[2]
+ span = span[3:]
+ return RecoveryCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.recovery_type > 255:
+ print(
+ f"Invalid value for field RecoveryCapability::recovery_type: {self.recovery_type} > 255; the value will be truncated"
+ )
+ self.recovery_type &= 255
+ _span.append((self.recovery_type << 0))
+ if self.maximum_recovery_window_size > 255:
+ print(
+ f"Invalid value for field RecoveryCapability::maximum_recovery_window_size: {self.maximum_recovery_window_size} > 255; the value will be truncated"
+ )
+ self.maximum_recovery_window_size &= 255
+ _span.append((self.maximum_recovery_window_size << 0))
+ if self.maximum_number_of_media_packets_in_parity_code > 255:
+ print(
+ f"Invalid value for field RecoveryCapability::maximum_number_of_media_packets_in_parity_code: {self.maximum_number_of_media_packets_in_parity_code} > 255; the value will be truncated"
+ )
+ self.maximum_number_of_media_packets_in_parity_code &= 255
+ _span.append((self.maximum_number_of_media_packets_in_parity_code << 0))
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 3
+
+
+@dataclass
+class ContentProtectionCapability(ServiceCapability):
+ cp_type: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.CONTENT_PROTECTION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["ContentProtectionCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.CONTENT_PROTECTION:
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ value_ = int.from_bytes(span[0:2], byteorder="little")
+ fields["cp_type"] = value_
+ span = span[2:]
+ payload = span
+ span = bytes([])
+ fields["payload"] = payload
+ return ContentProtectionCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.cp_type > 65535:
+ print(
+ f"Invalid value for field ContentProtectionCapability::cp_type: {self.cp_type} > 65535; the value will be truncated"
+ )
+ self.cp_type &= 65535
+ _span.extend(int.to_bytes((self.cp_type << 0), length=2, byteorder="little"))
+ _span.extend(payload or self.payload or [])
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return len(self.payload) + 2
+
+
+@dataclass
+class HeaderCompressionCapability(ServiceCapability):
+ recovery: int = field(kw_only=True, default=0)
+ media: int = field(kw_only=True, default=0)
+ back_ch: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.HEADER_COMPRESSION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["HeaderCompressionCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.HEADER_COMPRESSION:
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["recovery"] = (span[0] >> 5) & 0x1
+ fields["media"] = (span[0] >> 6) & 0x1
+ fields["back_ch"] = (span[0] >> 7) & 0x1
+ span = span[1:]
+ return HeaderCompressionCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.recovery > 1:
+ print(
+ f"Invalid value for field HeaderCompressionCapability::recovery: {self.recovery} > 1; the value will be truncated"
+ )
+ self.recovery &= 1
+ if self.media > 1:
+ print(
+ f"Invalid value for field HeaderCompressionCapability::media: {self.media} > 1; the value will be truncated"
+ )
+ self.media &= 1
+ if self.back_ch > 1:
+ print(
+ f"Invalid value for field HeaderCompressionCapability::back_ch: {self.back_ch} > 1; the value will be truncated"
+ )
+ self.back_ch &= 1
+ _value = (self.recovery << 5) | (self.media << 6) | (self.back_ch << 7)
+ _span.append(_value)
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class MultiplexingCapability(ServiceCapability):
+ frag: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.MULTIPLEXING
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["MultiplexingCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.MULTIPLEXING:
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["frag"] = (span[0] >> 7) & 0x1
+ span = span[1:]
+ payload = span
+ span = bytes([])
+ fields["payload"] = payload
+ return MultiplexingCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.frag > 1:
+ print(f"Invalid value for field MultiplexingCapability::frag: {self.frag} > 1; the value will be truncated")
+ self.frag &= 1
+ _span.append((self.frag << 7))
+ _span.extend(payload or self.payload or [])
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return len(self.payload) + 1
+
+
+@dataclass
+class MediaCodecCapability(ServiceCapability):
+ media_type: int = field(kw_only=True, default=0)
+ media_codec_type: int = field(kw_only=True, default=0)
+ media_codec_specific_information_elements: bytearray = field(kw_only=True, default_factory=bytearray)
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.MEDIA_CODEC
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["MediaCodecCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.MEDIA_CODEC:
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["media_type"] = (span[0] >> 4) & 0xF
+ fields["media_codec_type"] = span[1]
+ span = span[2:]
+ fields["media_codec_specific_information_elements"] = list(span)
+ span = bytes()
+ return MediaCodecCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.media_type > 15:
+ print(
+ f"Invalid value for field MediaCodecCapability::media_type: {self.media_type} > 15; the value will be truncated"
+ )
+ self.media_type &= 15
+ _span.append((self.media_type << 4))
+ if self.media_codec_type > 255:
+ print(
+ f"Invalid value for field MediaCodecCapability::media_codec_type: {self.media_codec_type} > 255; the value will be truncated"
+ )
+ self.media_codec_type &= 255
+ _span.append((self.media_codec_type << 0))
+ _span.extend(self.media_codec_specific_information_elements)
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return len(self.media_codec_specific_information_elements) * 1 + 2
+
+
+@dataclass
+class DelayReportingCapability(ServiceCapability):
+
+ def __post_init__(self):
+ self.service_category = ServiceCategory.DELAY_REPORTING
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DelayReportingCapability", bytes]:
+ if fields["service_category"] != ServiceCategory.DELAY_REPORTING:
+ raise Exception("Invalid constraint field values")
+ return DelayReportingCapability(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return ServiceCapability.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class SignalingPacket(Packet):
+ message_type: MessageType = field(kw_only=True, default=MessageType.COMMAND)
+ packet_type: PacketType = field(kw_only=True, default=PacketType.SINGLE_PACKET)
+ transaction_label: int = field(kw_only=True, default=0)
+ signal_identifier: SignalIdentifier = field(kw_only=True, default=SignalIdentifier.AVDTP_DISCOVER)
+
+ def __post_init__(self):
+ pass
+
+ @staticmethod
+ def parse(span: bytes) -> Tuple["SignalingPacket", bytes]:
+ fields = {"payload": None}
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["message_type"] = MessageType.from_int((span[0] >> 0) & 0x3)
+ fields["packet_type"] = PacketType.from_int((span[0] >> 2) & 0x3)
+ fields["transaction_label"] = (span[0] >> 4) & 0xF
+ fields["signal_identifier"] = SignalIdentifier.from_int((span[1] >> 0) & 0x3F)
+ span = span[2:]
+ payload = span
+ span = bytes([])
+ fields["payload"] = payload
+ try:
+ child, remain = DiscoverCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = DiscoverResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = DiscoverReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetCapabilitiesCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetCapabilitiesResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetCapabilitiesReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetAllCapabilitiesCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetAllCapabilitiesResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetAllCapabilitiesReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SetConfigurationCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SetConfigurationResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SetConfigurationReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetConfigurationCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetConfigurationResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GetConfigurationReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = ReconfigureCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = ReconfigureResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = ReconfigureReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = OpenCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = OpenResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = OpenReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = StartCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = StartResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = StartReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = CloseCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = CloseResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = CloseReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SuspendCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SuspendResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SuspendReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = AbortCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = AbortResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SecurityControlCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SecurityControlResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = SecurityControlReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = GeneralReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = DelayReportCommand.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = DelayReportResponse.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ try:
+ child, remain = DelayReportReject.parse(fields.copy(), payload)
+ assert len(remain) == 0
+ return child, span
+ except Exception as exn:
+ pass
+ return SignalingPacket(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.transaction_label > 15:
+ print(
+ f"Invalid value for field SignalingPacket::transaction_label: {self.transaction_label} > 15; the value will be truncated"
+ )
+ self.transaction_label &= 15
+ _value = ((self.message_type << 0) | (self.packet_type << 2) | (self.transaction_label << 4))
+ _span.append(_value)
+ _span.append((self.signal_identifier << 0))
+ _span.extend(payload or self.payload or [])
+ return bytes(_span)
+
+ @property
+ def size(self) -> int:
+ return len(self.payload) + 2
+
+
+@dataclass
+class DiscoverCommand(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_DISCOVER
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DiscoverCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_DISCOVER):
+ raise Exception("Invalid constraint field values")
+ return DiscoverCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class DiscoverResponse(SignalingPacket):
+ seid_information: List[SeidInformation] = field(kw_only=True, default_factory=list)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_DISCOVER
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DiscoverResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_DISCOVER):
+ raise Exception("Invalid constraint field values")
+ if len(span) % 2 != 0:
+ raise Exception("Array size is not a multiple of the element size")
+ seid_information_count = int(len(span) / 2)
+ seid_information = []
+ for n in range(seid_information_count):
+ seid_information.append(SeidInformation.parse_all(span[n * 2:(n + 1) * 2]))
+ fields["seid_information"] = seid_information
+ span = bytes()
+ return DiscoverResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ for _elt in self.seid_information:
+ _span.extend(_elt.serialize())
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return sum([elt.size for elt in self.seid_information])
+
+
+@dataclass
+class DiscoverReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_DISCOVER
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DiscoverReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_DISCOVER):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return DiscoverReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class GetCapabilitiesCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_CAPABILITIES
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetCapabilitiesCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_CAPABILITIES):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return GetCapabilitiesCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field GetCapabilitiesCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class GetCapabilitiesResponse(SignalingPacket):
+ service_capabilities: List[ServiceCapability] = field(kw_only=True, default_factory=list)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_CAPABILITIES
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetCapabilitiesResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_CAPABILITIES):
+ raise Exception("Invalid constraint field values")
+ service_capabilities = []
+ while len(span) > 0:
+ element, span = ServiceCapability.parse(span)
+ service_capabilities.append(element)
+ fields["service_capabilities"] = service_capabilities
+ return GetCapabilitiesResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ for _elt in self.service_capabilities:
+ _span.extend(_elt.serialize())
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return sum([elt.size for elt in self.service_capabilities])
+
+
+@dataclass
+class GetCapabilitiesReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_CAPABILITIES
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetCapabilitiesReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_CAPABILITIES):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return GetCapabilitiesReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class GetAllCapabilitiesCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_ALL_CAPABILITIES
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetAllCapabilitiesCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_ALL_CAPABILITIES):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return GetAllCapabilitiesCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field GetAllCapabilitiesCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class GetAllCapabilitiesResponse(SignalingPacket):
+ service_capabilities: List[ServiceCapability] = field(kw_only=True, default_factory=list)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_ALL_CAPABILITIES
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetAllCapabilitiesResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_ALL_CAPABILITIES):
+ raise Exception("Invalid constraint field values")
+ service_capabilities = []
+ while len(span) > 0:
+ element, span = ServiceCapability.parse(span)
+ service_capabilities.append(element)
+ fields["service_capabilities"] = service_capabilities
+ return GetAllCapabilitiesResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ for _elt in self.service_capabilities:
+ _span.extend(_elt.serialize())
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return sum([elt.size for elt in self.service_capabilities])
+
+
+@dataclass
+class GetAllCapabilitiesReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_ALL_CAPABILITIES
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetAllCapabilitiesReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_ALL_CAPABILITIES):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return GetAllCapabilitiesReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class SetConfigurationCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+ int_seid: int = field(kw_only=True, default=0)
+ service_capabilities: List[ServiceCapability] = field(kw_only=True, default_factory=list)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_SET_CONFIGURATION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SetConfigurationCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SET_CONFIGURATION):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ fields["int_seid"] = (span[1] >> 2) & 0x3F
+ span = span[2:]
+ service_capabilities = []
+ while len(span) > 0:
+ element, span = ServiceCapability.parse(span)
+ service_capabilities.append(element)
+ fields["service_capabilities"] = service_capabilities
+ return SetConfigurationCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field SetConfigurationCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ if self.int_seid > 63:
+ print(
+ f"Invalid value for field SetConfigurationCommand::int_seid: {self.int_seid} > 63; the value will be truncated"
+ )
+ self.int_seid &= 63
+ _span.append((self.int_seid << 2))
+ for _elt in self.service_capabilities:
+ _span.extend(_elt.serialize())
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return sum([elt.size for elt in self.service_capabilities]) + 2
+
+
+@dataclass
+class SetConfigurationResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_SET_CONFIGURATION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SetConfigurationResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SET_CONFIGURATION):
+ raise Exception("Invalid constraint field values")
+ return SetConfigurationResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class SetConfigurationReject(SignalingPacket):
+ service_category: int = field(kw_only=True, default=0)
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_SET_CONFIGURATION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SetConfigurationReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SET_CONFIGURATION):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["service_category"] = span[0]
+ fields["error_code"] = ErrorCode.from_int(span[1])
+ span = span[2:]
+ return SetConfigurationReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.service_category > 255:
+ print(
+ f"Invalid value for field SetConfigurationReject::service_category: {self.service_category} > 255; the value will be truncated"
+ )
+ self.service_category &= 255
+ _span.append((self.service_category << 0))
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 2
+
+
+@dataclass
+class GetConfigurationCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_CONFIGURATION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetConfigurationCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_CONFIGURATION):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return GetConfigurationCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field GetConfigurationCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class GetConfigurationResponse(SignalingPacket):
+ service_capabilities: List[ServiceCapability] = field(kw_only=True, default_factory=list)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_CONFIGURATION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetConfigurationResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_CONFIGURATION):
+ raise Exception("Invalid constraint field values")
+ service_capabilities = []
+ while len(span) > 0:
+ element, span = ServiceCapability.parse(span)
+ service_capabilities.append(element)
+ fields["service_capabilities"] = service_capabilities
+ return GetConfigurationResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ for _elt in self.service_capabilities:
+ _span.extend(_elt.serialize())
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return sum([elt.size for elt in self.service_capabilities])
+
+
+@dataclass
+class GetConfigurationReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_GET_CONFIGURATION
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GetConfigurationReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_GET_CONFIGURATION):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return GetConfigurationReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class ReconfigureCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+ service_capabilities: List[ServiceCapability] = field(kw_only=True, default_factory=list)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_RECONFIGURE
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["ReconfigureCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_RECONFIGURE):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ service_capabilities = []
+ while len(span) > 0:
+ element, span = ServiceCapability.parse(span)
+ service_capabilities.append(element)
+ fields["service_capabilities"] = service_capabilities
+ return ReconfigureCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field ReconfigureCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ for _elt in self.service_capabilities:
+ _span.extend(_elt.serialize())
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return sum([elt.size for elt in self.service_capabilities]) + 1
+
+
+@dataclass
+class ReconfigureResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_RECONFIGURE
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["ReconfigureResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_RECONFIGURE):
+ raise Exception("Invalid constraint field values")
+ return ReconfigureResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class ReconfigureReject(SignalingPacket):
+ service_category: int = field(kw_only=True, default=0)
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_RECONFIGURE
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["ReconfigureReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_RECONFIGURE):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["service_category"] = span[0]
+ fields["error_code"] = ErrorCode.from_int(span[1])
+ span = span[2:]
+ return ReconfigureReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.service_category > 255:
+ print(
+ f"Invalid value for field ReconfigureReject::service_category: {self.service_category} > 255; the value will be truncated"
+ )
+ self.service_category &= 255
+ _span.append((self.service_category << 0))
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 2
+
+
+@dataclass
+class OpenCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_OPEN
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["OpenCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_OPEN):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return OpenCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(f"Invalid value for field OpenCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class OpenResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_OPEN
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["OpenResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_OPEN):
+ raise Exception("Invalid constraint field values")
+ return OpenResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class OpenReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_OPEN
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["OpenReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_OPEN):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return OpenReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class StartCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_START
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["StartCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_START):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return StartCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(f"Invalid value for field StartCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class StartResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_START
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["StartResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_START):
+ raise Exception("Invalid constraint field values")
+ return StartResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class StartReject(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_START
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["StartReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_START):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ fields["error_code"] = ErrorCode.from_int(span[1])
+ span = span[2:]
+ return StartReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(f"Invalid value for field StartReject::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 2
+
+
+@dataclass
+class CloseCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_CLOSE
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["CloseCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_CLOSE):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return CloseCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 255:
+ print(f"Invalid value for field CloseCommand::acp_seid: {self.acp_seid} > 255; the value will be truncated")
+ self.acp_seid &= 255
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class CloseResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_CLOSE
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["CloseResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_CLOSE):
+ raise Exception("Invalid constraint field values")
+ return CloseResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class CloseReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_CLOSE
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["CloseReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_CLOSE):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return CloseReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class SuspendCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_SUSPEND
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SuspendCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SUSPEND):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return SuspendCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field SuspendCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class SuspendResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_SUSPEND
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SuspendResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SUSPEND):
+ raise Exception("Invalid constraint field values")
+ return SuspendResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class SuspendReject(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_SUSPEND
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SuspendReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SUSPEND):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 2:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ fields["error_code"] = ErrorCode.from_int(span[1])
+ span = span[2:]
+ return SuspendReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(f"Invalid value for field SuspendReject::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 2
+
+
+@dataclass
+class AbortCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_ABORT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["AbortCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_ABORT):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ return AbortCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(f"Invalid value for field AbortCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated")
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class AbortResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_ABORT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["AbortResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_ABORT):
+ raise Exception("Invalid constraint field values")
+ return AbortResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class SecurityControlCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+ content_protection_data: bytearray = field(kw_only=True, default_factory=bytearray)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_SECURITY_CONTROL
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SecurityControlCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SECURITY_CONTROL):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ span = span[1:]
+ fields["content_protection_data"] = list(span)
+ span = bytes()
+ return SecurityControlCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field SecurityControlCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ _span.extend(self.content_protection_data)
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return len(self.content_protection_data) * 1 + 1
+
+
+@dataclass
+class SecurityControlResponse(SignalingPacket):
+ content_protection_data: bytearray = field(kw_only=True, default_factory=bytearray)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_SECURITY_CONTROL
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SecurityControlResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SECURITY_CONTROL):
+ raise Exception("Invalid constraint field values")
+ fields["content_protection_data"] = list(span)
+ span = bytes()
+ return SecurityControlResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.extend(self.content_protection_data)
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return len(self.content_protection_data) * 1
+
+
+@dataclass
+class SecurityControlReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_SECURITY_CONTROL
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["SecurityControlReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_SECURITY_CONTROL):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return SecurityControlReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
+
+
+@dataclass
+class GeneralReject(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.GENERAL_REJECT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["GeneralReject", bytes]:
+ if fields["message_type"] != MessageType.GENERAL_REJECT:
+ raise Exception("Invalid constraint field values")
+ return GeneralReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class DelayReportCommand(SignalingPacket):
+ acp_seid: int = field(kw_only=True, default=0)
+ delay_msb: int = field(kw_only=True, default=0)
+ delay_lsb: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ self.message_type = MessageType.COMMAND
+ self.signal_identifier = SignalIdentifier.AVDTP_DELAYREPORT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DelayReportCommand", bytes]:
+ if (fields["message_type"] != MessageType.COMMAND or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_DELAYREPORT):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 3:
+ raise Exception("Invalid packet size")
+ fields["acp_seid"] = (span[0] >> 2) & 0x3F
+ fields["delay_msb"] = span[1]
+ fields["delay_lsb"] = span[2]
+ span = span[3:]
+ return DelayReportCommand(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.acp_seid > 63:
+ print(
+ f"Invalid value for field DelayReportCommand::acp_seid: {self.acp_seid} > 63; the value will be truncated"
+ )
+ self.acp_seid &= 63
+ _span.append((self.acp_seid << 2))
+ if self.delay_msb > 255:
+ print(
+ f"Invalid value for field DelayReportCommand::delay_msb: {self.delay_msb} > 255; the value will be truncated"
+ )
+ self.delay_msb &= 255
+ _span.append((self.delay_msb << 0))
+ if self.delay_lsb > 255:
+ print(
+ f"Invalid value for field DelayReportCommand::delay_lsb: {self.delay_lsb} > 255; the value will be truncated"
+ )
+ self.delay_lsb &= 255
+ _span.append((self.delay_lsb << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 3
+
+
+@dataclass
+class DelayReportResponse(SignalingPacket):
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_ACCEPT
+ self.signal_identifier = SignalIdentifier.AVDTP_DELAYREPORT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DelayReportResponse", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_ACCEPT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_DELAYREPORT):
+ raise Exception("Invalid constraint field values")
+ return DelayReportResponse(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+
+@dataclass
+class DelayReportReject(SignalingPacket):
+ error_code: ErrorCode = field(kw_only=True, default=ErrorCode.SUCCESS)
+
+ def __post_init__(self):
+ self.message_type = MessageType.RESPONSE_REJECT
+ self.signal_identifier = SignalIdentifier.AVDTP_DELAYREPORT
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple["DelayReportReject", bytes]:
+ if (fields["message_type"] != MessageType.RESPONSE_REJECT or
+ fields["signal_identifier"] != SignalIdentifier.AVDTP_DELAYREPORT):
+ raise Exception("Invalid constraint field values")
+ if len(span) < 1:
+ raise Exception("Invalid packet size")
+ fields["error_code"] = ErrorCode.from_int(span[0])
+ span = span[1:]
+ return DelayReportReject(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ _span.append((self.error_code << 0))
+ return SignalingPacket.serialize(self, payload=bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 1
diff --git a/android/pandora/test/a2dp_test.py b/android/pandora/test/a2dp_test.py
index 05c5bedd7f..92df133d62 100644
--- a/android/pandora/test/a2dp_test.py
+++ b/android/pandora/test/a2dp_test.py
@@ -14,19 +14,19 @@
import asyncio
import avatar
+import bumble
import dataclasses
import itertools
import logging
import numpy as np
+from a2dp.packets import avdtp
from avatar import BumblePandoraDevice, PandoraDevice, PandoraDevices, pandora
from avatar.pandora_server import AndroidPandoraServer
-import bumble
-from bumble.avctp import AVCTP_PSM
from bumble.a2dp import (
A2DP_MPEG_2_4_AAC_CODEC_TYPE,
- MPEG_2_AAC_LC_OBJECT_TYPE,
A2DP_SBC_CODEC_TYPE,
+ MPEG_2_AAC_LC_OBJECT_TYPE,
SBC_DUAL_CHANNEL_MODE,
SBC_JOINT_STEREO_CHANNEL_MODE,
SBC_LOUDNESS_ALLOCATION_METHOD,
@@ -37,11 +37,29 @@ from bumble.a2dp import (
SbcMediaCodecInformation,
make_audio_sink_service_sdp_records,
)
-from bumble.avdtp import (AVDTP_AUDIO_MEDIA_TYPE, AVDTP_OPEN_STATE, AVDTP_PSM, AVDTP_STREAMING_STATE, AVDTP_IDLE_STATE,
- AVDTP_CLOSING_STATE, Listener, MediaCodecCapabilities, Protocol, AVDTP_BAD_STATE_ERROR,
- Suspend_Reject)
-from bumble.l2cap import (ChannelManager, ClassicChannel, ClassicChannelSpec, L2CAP_Configure_Request,
- L2CAP_Connection_Response, L2CAP_SIGNALING_CID)
+from bumble.avctp import AVCTP_PSM
+from bumble.avdtp import (
+ AVDTP_AUDIO_MEDIA_TYPE,
+ AVDTP_BAD_STATE_ERROR,
+ AVDTP_CLOSING_STATE,
+ AVDTP_IDLE_STATE,
+ AVDTP_OPEN_STATE,
+ AVDTP_PSM,
+ AVDTP_STREAMING_STATE,
+ AVDTP_TSEP_SRC,
+ Listener,
+ MediaCodecCapabilities,
+ Protocol,
+ Suspend_Reject,
+)
+from bumble.l2cap import (
+ L2CAP_SIGNALING_CID,
+ ChannelManager,
+ ClassicChannel,
+ ClassicChannelSpec,
+ L2CAP_Configure_Request,
+ L2CAP_Connection_Response,
+)
from bumble.pairing import PairingDelegate
from mobly import base_test, test_runner
from mobly.asserts import assert_equal # type: ignore
@@ -49,15 +67,15 @@ from mobly.asserts import assert_in # type: ignore
from mobly.asserts import assert_is_not_none # type: ignore
from mobly.asserts import fail # type: ignore
from pandora.a2dp_grpc_aio import A2DP
-from pandora.a2dp_pb2 import PlaybackAudioRequest, Source, Configuration, STEREO
+from pandora.a2dp_pb2 import STEREO, Configuration, PlaybackAudioRequest, Source
from pandora.host_pb2 import Connection
from pandora.security_pb2 import LEVEL2
from typing import Optional, Tuple
logger = logging.getLogger(__name__)
-AVRCP_CONNECT_A2DP_WITH_DELAY = 'com.android.bluetooth.flags.avrcp_connect_a2dp_with_delay'
AVDTP_HANDLE_SUSPEND_CFM_BAD_STATE = 'com.android.bluetooth.flags.avdt_handle_suspend_cfm_bad_state'
+AVDTP_HANDLE_SIGNALING_ON_PEER_FAILURE = 'com.android.bluetooth.flags.avdt_handle_signaling_on_peer_failure'
async def initiate_pairing(device, address) -> Connection:
@@ -280,13 +298,6 @@ class A2dpTest(base_test.BaseTestClass): # type: ignore[misc]
3. Check AVDTP status on RD1
"""
- # Enable AVRCP connect A2DP delayed feature
- for server in self.devices._servers:
- if isinstance(server, AndroidPandoraServer):
- server.device.adb.shell(['device_config override bluetooth', AVRCP_CONNECT_A2DP_WITH_DELAY,
- 'true']) # type: ignore
- break
-
# Connect and pair RD1.
ref1_dut, dut_ref1 = await asyncio.gather(
initiate_pairing(self.ref1, self.dut.address),
@@ -353,17 +364,19 @@ class A2dpTest(base_test.BaseTestClass): # type: ignore[misc]
def on_l2cap_connection_request(self, connection: Connection, cid: int, request) -> None:
global pending_configuration_request
- if (request.psm == AVDTP_PSM and pending_configuration_request is not None):
+ if request.psm == AVDTP_PSM and pending_configuration_request is not None:
logger.info("<< 4. RD1 rejects AVDTP connection request from DUT >>")
self.send_control_frame(
- connection, cid,
+ connection,
+ cid,
L2CAP_Connection_Response(
identifier=request.identifier,
destination_cid=0,
source_cid=request.source_cid,
result=L2CAP_Connection_Response.CONNECTION_REFUSED_NO_RESOURCES_AVAILABLE,
status=0x0000,
- ))
+ ),
+ )
logger.info("<< 5. RD1 proceeds with first AVDTP channel configuration >>")
chan_connection = pending_configuration_request.connection
chan_cid = pending_configuration_request.cid
@@ -377,14 +390,15 @@ class A2dpTest(base_test.BaseTestClass): # type: ignore[misc]
def on_connection_response(self, response):
assert self.state == self.State.WAIT_CONNECT_RSP
- assert response.result == L2CAP_Connection_Response.CONNECTION_SUCCESSFUL, f"Connection response: {response}"
+ assert (response.result == L2CAP_Connection_Response.CONNECTION_SUCCESSFUL
+ ), f"Connection response: {response}"
self.destination_cid = response.destination_cid
self._change_state(self.State.WAIT_CONFIG)
logger.info("<< 2. RD1 connected DUT, configuration postponed >>")
def on_configure_request(self, request) -> None:
global pending_configuration_request
- if (pending_configuration_request is not None):
+ if pending_configuration_request is not None:
logger.info("<< 3. Block RD1 until DUT tries AVDTP channel connection >>")
pending_configuration_request.connection = self.connection
pending_configuration_request.cid = self.source_cid
@@ -648,6 +662,76 @@ class A2dpTest(base_test.BaseTestClass): # type: ignore[misc]
# Wait for AVDTP Close
await asyncio.wait_for(avdtp_future, timeout=10.0)
+ @avatar.asynchronous
+ async def test_avdt_open_after_timeout(self) -> None:
+ """Test AVDTP automatically opens stream after timeout if peer device only configures codec.
+
+ 1. Pair and Connect RD1 -> DUT
+ 2. Connect AVDTP RD1 -> DUT but do not send AVDT Open Command
+ 3. Check that the DUT will abort and reopen the AVDTP as initiator
+ """
+
+ class TestAvdtProtocol(Protocol):
+
+ def on_open_command(self, command):
+ nonlocal avdtp_future
+ logger.info("<< AVDTP Open received >>")
+ avdtp_future.set_result(None)
+ return super().on_open_command(command)
+
+ # Enable BAD_STATE handling
+ for server in self.devices._servers:
+ if isinstance(server, AndroidPandoraServer):
+ server.device.adb.shell(
+ ['device_config override bluetooth', AVDTP_HANDLE_SIGNALING_ON_PEER_FAILURE,
+ 'true']) # type: ignore
+ break
+
+ # Connect and pair RD1.
+ ref1_dut, dut_ref1 = await asyncio.gather(
+ initiate_pairing(self.ref1, self.dut.address),
+ accept_pairing(self.dut, self.ref1.address),
+ )
+
+ # Create a listener to wait for AVDTP open
+ avdtp_future = asyncio.get_running_loop().create_future()
+
+ # Retrieve Bumble connection object from Pandora connection token
+ connection = pandora.get_raw_connection(device=self.ref1, connection=ref1_dut)
+ assert connection is not None
+
+ channel = await connection.create_l2cap_channel(spec=ClassicChannelSpec(psm=AVDTP_PSM))
+ client = TestAvdtProtocol(channel)
+ sink = client.add_sink(sbc_codec_capabilities())
+ endpoints = await client.discover_remote_endpoints()
+ logger.info(f"endpoints: {endpoints}")
+ assert len(endpoints) >= 1
+ remote_source = list(endpoints)[0]
+ assert remote_source.in_use == 0
+ assert remote_source.media_type == AVDTP_AUDIO_MEDIA_TYPE
+ assert remote_source.tsep == AVDTP_TSEP_SRC
+ logger.info(f"remote_source: {remote_source}")
+
+ configuration = MediaCodecCapabilities(
+ media_type=AVDTP_AUDIO_MEDIA_TYPE,
+ media_codec_type=A2DP_SBC_CODEC_TYPE,
+ media_codec_information=SbcMediaCodecInformation.from_lists(
+ sampling_frequencies=[44100],
+ channel_modes=[SBC_JOINT_STEREO_CHANNEL_MODE],
+ block_lengths=[16],
+ subbands=[8],
+ allocation_methods=[SBC_LOUDNESS_ALLOCATION_METHOD],
+ minimum_bitpool_value=2,
+ maximum_bitpool_value=53,
+ ),
+ )
+
+ response = await remote_source.set_configuration(sink.seid, [configuration])
+ logger.info(f"response: {response}")
+
+ # Wait for AVDTP Open from DUT
+ await asyncio.wait_for(avdtp_future, timeout=10.0)
+
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
diff --git a/apex/Android.bp b/apex/Android.bp
index 52b9631fb4..4eccda2a11 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -1,10 +1,19 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_bt_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_bt_license"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
linker_config {
@@ -13,7 +22,8 @@ linker_config {
installable: false,
}
-// Mainline bluetooth apex module.
+// Legacy Bluetooth apex prior to Baklava
+// TODO b/383863941 delete
apex {
name: "com.android.btservices",
defaults: ["t-launched-apex-module"],
@@ -121,7 +131,6 @@ bootclasspath_fragment {
"com.android.bluetooth",
],
},
-
}
systemserverclasspath_fragment {
@@ -129,3 +138,110 @@ systemserverclasspath_fragment {
standalone_contents: ["service-bluetooth"],
apex_available: ["com.android.btservices"],
}
+
+// Mainline bluetooth apex module.
+apex {
+ name: "com.android.bt",
+ defaults: ["b-launched-apex-module"],
+ // TODO b/356727632: remove min_sdk_version as this is set from b-launched-apex-module
+ min_sdk_version: "35",
+ manifest: "manifest.json",
+ bootclasspath_fragments: ["com.android.bt-bootclasspath-fragment"],
+ systemserverclasspath_fragments: ["com.android.bt-systemserverclasspath-fragment"],
+ file_contexts: ":com.android.bt-file_contexts",
+ compat_configs: [
+ "bluetooth-compat-config",
+ "bluetoothapk-platform-compat-config",
+ "framework-bluetooth-compat-config",
+ ],
+ apps: ["Bluetooth"],
+
+ multilib: {
+ first: {
+ // Extractor process runs only with the primary ABI.
+ jni_libs: [
+ "libbluetooth_jni",
+ ],
+ },
+ },
+
+ prebuilts: [
+ "audio_set_configurations_bfbs",
+ "audio_set_configurations_json",
+ "audio_set_scenarios_bfbs",
+ "audio_set_scenarios_json",
+ "bt_did.conf",
+ "bt_stack.conf",
+ "interop_database.conf",
+ ],
+ key: "com.android.bt.key",
+ certificate: ":com.android.bt.certificate",
+ updatable: true,
+ compressible: false,
+ visibility: ["//packages/modules/common/build"],
+}
+
+sdk {
+ name: "bt-module-sdk",
+ apexes: [
+ // Adds exportable dependencies of the APEX to the sdk,
+ // e.g. *classpath_fragments.
+ "com.android.bt",
+ ],
+}
+
+// Encapsulate the contributions made by the com.android.bluetooth to the bootclasspath.
+bootclasspath_fragment {
+ name: "com.android.bt-bootclasspath-fragment",
+ contents: ["framework-bluetooth"],
+ apex_available: ["com.android.bt"],
+
+ // The bootclasspath_fragments that provide APIs on which this depends.
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+
+ // Additional stubs libraries that this fragment's contents use which are
+ // not provided by another bootclasspath_fragment.
+ additional_stubs: [
+ "android-non-updatable",
+ ],
+
+ // Additional hidden API flag files to override the defaults. This must only be
+ // modified by the Soong or platform compat team.
+ hidden_api: {
+ max_target_o_low_priority: ["hiddenapi/hiddenapi-max-target-o-low-priority.txt"],
+ max_target_r_low_priority: ["hiddenapi/hiddenapi-max-target-r-low-priority.txt"],
+ unsupported: ["hiddenapi/hiddenapi-unsupported.txt"],
+
+ // The following packages contain classes from other modules on the
+ // bootclasspath. That means that the hidden API flags for this module
+ // has to explicitly list every single class this module provides in
+ // that package to differentiate them from the classes provided by other
+ // modules. That can include private classes that are not part of the
+ // API.
+ split_packages: [
+ "android.bluetooth",
+ ],
+
+ // The following packages and all their subpackages currently only
+ // contain classes from this bootclasspath_fragment. Listing a package
+ // here won't prevent other bootclasspath modules from adding classes in
+ // any of those packages but it will prevent them from adding those
+ // classes into an API surface, e.g. public, system, etc.. Doing so will
+ // result in a build failure due to inconsistent flags.
+ package_prefixes: [
+ "android.bluetooth.le",
+ "com.android.bluetooth",
+ ],
+ },
+}
+
+systemserverclasspath_fragment {
+ name: "com.android.bt-systemserverclasspath-fragment",
+ standalone_contents: ["service-bluetooth-new"],
+ apex_available: ["com.android.bt"],
+}
diff --git a/apex/hiddenapi/OWNERS b/apex/hiddenapi/OWNERS
index 82b599dbf1..ac8a2b627c 100644
--- a/apex/hiddenapi/OWNERS
+++ b/apex/hiddenapi/OWNERS
@@ -1,7 +1,3 @@
-# These files are only intended to be changed by platform-compat and
-# the soong teams.
-set noparent
-
# soong-team@ as the hiddenapi files are tightly coupled with Soong
file:platform/build/soong:/OWNERS
diff --git a/apex/key.pem b/apex/key.pem
deleted file mode 100644
index 527a032e89..0000000000
--- a/apex/key.pem
+++ /dev/null
@@ -1,52 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCzjMPKWIQ0dP75
-H8VFPNKgK/rXTdoAeZ7+lKtfSpbHwDvkgES168JphH8OoIf9CUBk6d1/cw/N/V54
-ZhIn5hwEZcE1DaeKRSull3prRwFo5enhJBXerNNqw8IHNw4RIRqeKNxJh0HfVLmc
-C0UpDVC7dW2CbDI7DcLb0DQN5I3W4NChlcv7XVysn5mJXK9EDk502goumlxfjl8w
-UR/RV6XcKn5dt0QG7enUOQQ3Q/EqY87jeFLb/aGloSbLcwzYny/VLNF3JOPYW1y/
-8fYlTUP1FQ8o47yImRNYuAJ7ATxVV0KFlHj+Hq9goFPi/98TjNMdLSwuUmGsIDPT
-wFufE0hQAH9bNzAczL4Q7QBqpng8vCFZ8HZQFfj+au7/YGygvjv9p5ex9CLn4zw2
-t+dRH4oNQG71IKpj2dKm8NVYsMkoxWE5CbZAFgKI8egNEEKWSRDG0GRAncJ4fk96
-5+hqat32gFykmLxkkIO0xaiLQh7h0lFz1vgD/bkaTE7CFLI14gaZ2ereixIrp/WC
-sN5+LoabG9NyTK8ExDQ5LgGN9ozCqnAakd7o0VmcMHep9A+rAY5ZzAKFMVqhqOQ7
-8ROC/2bpFB6U4E1BsHWUrc+ZwhvUgLf3GrkGndtxvQN1MD9wq6cTiSMM0T7MVJpM
-Mqh7EHpO0qNNYwwHqFCDHorBk1ZxzwIDAQABAoICAGXfODdWgaxBtWkj3YmrONYo
-HeqLAWXDm7JWJ+WpLGOpblH3dQTC/0tfIbfq3T10QlT/W+00G4OEflVRlHuO09aq
-5TR0ytpo5JrPl2XGo8YgrNJQ5xewd0PcTfpKAnE1lySlilctpvJP3//pZRQlueii
-d7/II7fd1vFg8CfxxYhlhfooQ9Qa5LoM09BcBhVXCKzECYLnkgGlhdykKqlcUX7Z
-nVkO4koMMt92ei3hHrQubPQjEOBAx7Zx+ND2NhOyPjF1fGNdSuk27Sj63+3KKQSl
-LjTFAfN+5rsvrDieOt0w5U1lMED+qALq9K2W/7rX6/Bh8O9XTpOasc0zFsjq59uI
-b+uBsZIPaGDpTjkYBKK3xrhNqIuq2ylN+0D14uAK4/z4sXsvP1XymjWkVNR9ii45
-doiDxANvZzqYoXcR5aEkJcO126RbDIw/SIglWTag6mRvNYCnLVcTzVf7uZXFyLXc
-Yk0NpTGAphVl4uVjXFgr8ZXfQIoM51zFvVVh3+dhosNGms1lgcvGHzJRKsOCzaA8
-EdWm3mGZrM8kvviqFoS4PndIIz6hB71MGhISEWbTUssF/AJSDWKdvJEWpTSLUjyY
-OoWaTABjZEjyCXpaIvssQilyOb+UVP6ayMAyfDjz5lDKB2216PhoQ9sOb9fIDrdK
-24XwqdMUqDZJV6GY8nQBAoIBAQDnS1DTUYeQwO1C831d1m8P8PhEDpwioBPv53y/
-owbmbwADTMxWvRfGnmXM5BYAeiDFfECp2HPnB5SGpkXOJOQ8H8WStgkhRglNHBbK
-yDaoLYTZqkk49enYEO6MNuFgTqiOWwgO+MVXPKmjreenhsoAQAKFFBPqyNU6v9a2
-WEHuIMc6Gv+2GkT7wkVwgmTZA1L58Y2EWX0wdDAYLS+0+6u+xJ5lPQI014Y7YNsa
-qvu7PG5gQ8fdU1fPmMRk9OOxiHilLc0GAQPtnF4fQYcNdcZ66FARMjHjZnFqHCPI
-irddmFReMkKj+HHufO6EVf8KkWgyIr9CzS9wh43PWW/CILwZAoIBAQDGuoM4DEV5
-tr+FmF3Rri1P0G+iC3Bm9oTa1S1AC4r8yPiY9Q8/lV009am2gbz6R5TFma+oFU1y
-R3pm6AaijeKmusmi2NGtdbqa9cUL98HtVAT7ZQmzyz9UepyZQmDy/0B4q2fGOUX1
-QnxKIOU2j8CFVUkbijUooRypZG7mIs/PsnTtmDb0JdOr54E26BLaBXbFcrxLuJxX
-STpQVbU3U/Y2jaLnRcPF4e6bCrQbrsH37wMLM3JTes8PRr0IcPDs4sp30Gj55rcL
-vSYZqfeVKadA312In5p4OPJV7/HSzRl4JE4JSWlCRLZepmAy36kFpQzI6N3LUVMp
-RuZtf+UXIVonAoIBAQCVLEIoyICCn6tmbtwAVXiz81prqnCQ9GVnaQlQH7knjZeY
-iUOQ/cwD0c0eZEy8aggQ1p5t7Khz7LOiVELZPXnmPSeUA8vHpgABt4gLqS13MkRo
-jidDkXcMX38693pMPu7/QT7lSRUduoY+hr7NkWVe2+nEIrrlxjmf9nJokGuVRZa4
-pwkdTbwIE7ftZGveewJdKal4Hq9bPNR4A0ytkVOnafAuozZ1FjwAt+sYPAa3L7aQ
-Z6bT3BjaT1D7O+ZObhJBllSQ9r6t1RfvWLfduoQUaRiavqDmZP/oy9VYVf8FYmWn
-iwrn7iitA+5hc4VWL4ngLADm+KcMEKEphilKLwqhAoIBAAC7FNpy6Rp+eovSOJ4Z
-xt7hRFfTNPGb/HcVi5oNsNAnKQre89RnBzW3pY0fQwOkmb50RzoWAffmnWOdfNDC
-NtAoJa+snnDF2w7Q0o2tto/Z3D7Ua0m2+J+l58eEf/jEyYboEnSfJ0u0l+Jp5o3h
-z3JuEtvAEVv547IXxXShMiRwYo+xHJqfPP0H1+jMx6z3ki09s8WPgzuq8ET1W7o9
-W81tjejNz999ajQ1wN3NMbdosJks8kGuVO6Ycv+B8tDcMKRqJsiseYXYhzhW8Ksi
-wROy/pQPCjFg/Dsmq7v7txlDAOp106ZDvGvyrq3hNqzno3llqdMilGy1bwl+C+ie
-3ccCggEBAISSVWD3owRf5n8unlVTmg64miLv3rM3s67F+Hn62qeyYmW3AhMSPyt2
-RIkEr2YrOKQ5D8Ijk3Gad4ae5UdyeCOPg495qk7bD5thcYG4Mo/MVvCQXxgdkeaK
-TFHpzzUttgKUe2EBfCbkxPjzWqf3ba0mvcnW621vUVA+VDqIUlBU9aosRMgDOFUi
-N+667Kj5P382oZHHxFnUZnCa3PczyGG3WLYBLRFAHl3n8kJ9mOUAAlVC8sRgcYmZ
-z2ZYfc22sUREah+kdxvDvR2ayopl86XoyrdTnK0XKEo+lU8Ghovc5Kbopf15KdWz
-/cAk+1ZkOAzn5RIZNaFGw2FKHds1ODQ=
------END PRIVATE KEY-----
diff --git a/apex/key/Android.bp b/apex/key/Android.bp
new file mode 100644
index 0000000000..7fb3ada21b
--- /dev/null
+++ b/apex/key/Android.bp
@@ -0,0 +1,16 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+apex_key {
+ name: "com.android.bt.key",
+ public_key: "com.android.bt.avbpubkey",
+ private_key: "com.android.bt.pem",
+ visibility: ["//packages/modules/Bluetooth/apex"],
+}
+
+android_app_certificate {
+ name: "com.android.bt.certificate",
+ certificate: "com.android.bt",
+ visibility: ["//packages/modules/Bluetooth/apex"],
+}
diff --git a/apex/key/com.android.bt.avbpubkey b/apex/key/com.android.bt.avbpubkey
new file mode 100644
index 0000000000..46122323d5
--- /dev/null
+++ b/apex/key/com.android.bt.avbpubkey
Binary files differ
diff --git a/apex/key/com.android.bt.pem b/apex/key/com.android.bt.pem
new file mode 100644
index 0000000000..90bda1b1b1
--- /dev/null
+++ b/apex/key/com.android.bt.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQConPWgz/jp7N6g
+7J1x8blR4w02RgiKQy0ViEbHo/UUOP1ctXxHz6Y0nmmAFCueiGbPgyjtlX0JNMki
+RX7wd988BZNzhc1ngmYuNsS36YKSkZg3DMnGr6xMWhEUEVKn2Exb+TUA3q3IFKny
+jrp637AJGebzLdgWldtdxxDqUU0xIRqggXL3UJAOHATPooQdpQ6dbHOr/jh68oYb
++FQE0gkjhh6ugNhMHNi6nQ+PwV0kacNy3cOPu/Kn6nTAw6OHdR+BXdL9IdOWO/rq
+bIDXByoM2bOH1XrcBa9FmFWD0HOf451X0fRi2JtAY6A1AqquFgVcLNS3Ai3eQfI+
+J4ElO9dOlFiawbFM8qJSu4bGwUM3jBjF8QmHaxt0lmHBdcJwBeY8G1dtVwctOFS1
+F9L5gQok9jZzmZDiIs6EzDmjTENJ0W1GF+KxN18s9hrEgdAD7gPRmE87pjhlmTI+
+LEgGxqduezLph1fpKYe6i/RdHUGQ8vEov6DulVzgjJATlI+TneLBWkzksILgsn2F
+lEMacEMCELY4jK06YL9N/CGSoPxa5T2RBIHCD8mjftfnSc2k3gt4sV+nsoXoA4n0
+PVb3n0cFNpY0egOaLCTtvqSsoFAC75K14MsumJ3KpBrs+A2tVtaXTt5HUbeqlhFa
+GRS6WJ89T/S/19fDCX8dq1nyNRv1EQIDAQABAoICABO9dYXPV15Gpp1LOlcW1EoN
+lZRFMHaEbRSsZNH2ZGjKz8HA9xT+ruAR7DrMEbvAjx3MBpiDE/WGFiaioX0EYbCY
+nAXONEkiI3WVYKRB7LEdZcdLIlvWIQs6z61MZmODX5Q0ebO5fjmyjp94vYUJZ2X3
+X/oYI8hoILuqxLSUEmAWNrR0F0o0Rrs6JUeMSKCiXHLKecPY8lKVjmUbpnV+hAai
+SvkF2VzW0zpMzT+4pP+QeMr7wsuS9tKZELRpKx3elNLL0dnkEg4QhVyY2aAjBPWm
+bp3wXK8B5N5WWmuhVcoSJy97A3wnjQyFpWHTZzlUl2nOT1SCJy3SRWqorBZYekk2
+fBgrLM9RRBByXpoWIzkB73BPBf7oifqYWjtQv26fxVNAnWPqoGF8KiSTEBCisPnI
+EhGoziOOPOfjsxg01G6iF2u/m/Cxys6UEafZlUJjvueovOCmomV8FylwlcoU/M1z
+Zvg0Xn2McqR0TmLXYlioSaJMLmAwm9tGpa2IXmQllkfszb7Figrso93q8O2NTxV0
+jEuzw8NU3ScPt8s21wtmxwmT9FxhS8f55uTo6h1IZPdgKRIDEF/ReTv5f7HLUnK+
+zIypddT3KbFhdlhD9/4OrLV9K5nVLXhhA5NfEtEOGqtywT6xOOVd9o5A3yyEomRI
+A91RYtECA1UkbIoOtWPpAoIBAQDb0TxtcUbbvTEMnDLT6X76RgebWyZ1Ycs1GR7g
+ZRNIrLwkWZYsU6H7BxcjKDNmS3PGdspJ7kwgBqp0lIM/OIYgZCuTynzbkFmZTtyQ
+uBcFtge3y4Wx9lmpJYKBrGDXbGcJX2iwzzxmTuGxF/RdP/xlKg2Jg/xbj/YNIZCn
+f2RD6ejuqrxCW2Qxy+jPplf1GpeMYZ96Kk6jUrc/XZXDBtyFGLUyQfG0RJ/oifRG
+yd6cjNKzKfFe6Pq6KZ+NsiPvgsng+qqsjXT0H0YUr31Cf/wAiXafMcwaxngKRktM
+i2uartskFptr1cet0hGdVCLopXyV4miTw8qP/0PIqZLAQgdJAoIBAQDEXg6ZBFAC
+BUa0UNLFbDNXMIVwjQ2dvYcNe+l9XvOOb38spHqIDUnzQ+y7nJ/eF12eAnFdnzZe
+dA0wC4bTwNUIS/Xq11HREPj+kr7ZOJdN4h0EzWKdiR+YMZ4TW/owg4epMtyz08/v
+mIaLVOL5nRL1TyNkXk4PcQo6ZnfygAmmOQGwyj1fzyT2ae7rg19/vKZNouCUpEZR
+irynMPyCD+TwNZii3knLO+bB6+lRMoVlvfeFb/MsF2G6f/Vv1uYHVY58NKUbjrrU
+UA7qjL1YtRrCfAXPLH0HUkSb2+rW49myMCqXourHwTGTMF2io036OD2bszro1f5p
+Ns8jMNBBqpeJAoIBAFyCYTj57EU8CPFypx1x7gNsB3WFVdkesAOHr+vl/cifEYsG
+vOGozMm1gTJFj+QkKvRCN/4HMLhltcTcX6PyqNfm8EQBeqx4wox3mPG6182KfxMF
+rx1nPPKnm5XxMsxWjcJvCcMnZBb2aZs7Jpc7/3+fxBS0nDb4jieWkac8QLkoLuSK
+rDIM/kzKsQ76xZecel0VFKW4OmIXxJEBVK7AK3xEGrWs9QjVvKqDrG9CM9KUnXPT
+WgaEbEh+jex3JRJ+a3GobL2zxp2ar8ay2DdtX2PmdiqnLWuzTP+d98CeCEoP/p/g
+d8ZZMPDhMJKSvyJDyvvVTgep5YzWc/N2EhGheCkCggEAWOZUKYZASonk9qFYqrRP
+kfuPjeLt9SnmyH3+uRmRnjxwEN/t8UZC4nUv6cgAwGVHps9oT4BS9vQHPGcbhSZZ
+y8XH8afFjKbocygwatsp9MKXbKMnMDbyLM7Zx93uKKSDeGBkdq1ACDK/RrkJgQRR
+nulTFo9zO55riQD28LxyoeRRFZ6ZppR7IWvYFJuHUqcvixpgHis5ApWSzwZoauGT
+PgSls6Z7Nh1KXSTWnkIHDoawVqLWLnHvdqWTkixyO4PKXAThctZtUs1j02AgINbs
+5HuNjbuQZw4hrYYkjWDeH8OapMfHDuQx83cEDSttlAh+K806sEqhQTTlFgN1ZSU8
+MQKCAQBwvij8CZ5LnNatLJo3mBC+dHmBSjIHvzAFvuVqeRarjPU0V4OubykZzDQ0
+9rxDwo3+Nd+hwlB+Di7BUTG7/yZDP8qNWMCker73sG1Z9ymgVzmKSx/Sgl0lOVcA
+/pZVTx1MX6pRjaM8WlrYLsFKq++95Gvj8Hk3TCsT6vl9IJ485jnS+xYP22YeU/Qh
+CGfqfcEnExJUx4AoNdhuVgpZ1/DXMFOgF2ETzxL4xLxDk9bGvM2HApLe084Es5MT
+mO2ugkGWJaabt+N0jIveIeIAbF7yJjrTPxLTJZnD9DwbXM5m9AGA8TVOq5ByrLpz
+OAbnJ6ncUN/kW2Ycz7J+ojDBHxcp
+-----END PRIVATE KEY-----
diff --git a/apex/key/com.android.bt.pk8 b/apex/key/com.android.bt.pk8
new file mode 100644
index 0000000000..8dc45f73ae
--- /dev/null
+++ b/apex/key/com.android.bt.pk8
Binary files differ
diff --git a/apex/key/com.android.bt.x509.pem b/apex/key/com.android.bt.x509.pem
new file mode 100644
index 0000000000..5c56158c3b
--- /dev/null
+++ b/apex/key/com.android.bt.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF6TCCA9GgAwIBAgIUDb1AaDxPOs2NLScNM0HjN5HDJxYwDQYJKoZIhvcNAQEL
+BQAwgZsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMRcwFQYDVQQD
+DA5jb20uYW5kcm9pZC5idDAgFw0yNDEyMTIyMzI1MjJaGA80NzYyMTEwODIzMjUy
+MlowgZsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMRcwFQYDVQQD
+DA5jb20uYW5kcm9pZC5idDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+ALII9yRq95uVLXRn7hai0yfwIaITGdD0md9wsdyj8pgEZkQq7hkBTdGZeSNB8KOo
+SkG9Teb9tgxlDcdSip45SX1snnpK0oZMXvHdmp4Wi6468kRte7MWr2Vv75RV6/Ye
+msnyczM9SGQKWOn8dF+aRo36YWD8k4xhpL3nIWM3WLH8D1q78WsLHPsvcVPTRfxe
+dq2/l5AoAgbCqCP+fofLTdW/X60Sp/jKs/LYT/XeuBfxpp4O7WVzXgnuXUZ+AdCZ
+jCeo3LJgb55Z/ITEByK3o4YV4Kp5/nzD9o48/GEXkc9n8SQF85WskHjv2ff4Uaah
+hnYKGIQ8CG3r3kD+hdV5o2AY+fvB66fsb/Q/VkeAR5I9Oj0CkoNwgfCc7ovU4FW4
+CbWvGBKUWChYlvEkmhtCGWKZX3sCiYUoSwlZmPI/HRFqs2YGSPda2d9XGEowu7j5
+EDRg83IOBNhBLzgpJ1iyb5uDadvGSxbC5DlXekNUzotmTQE5GRNLZMTud3HYmHft
+YuIXr9mZgAiUNi9pzsMpbJpaUrp/cBIQOdq/hFMfLixSyNg8pDaOAXZcEglYa1H7
+WvGi3C0Dk5PgfoIQh3wKqzb8wfJ77cFpD7uNUQ8+Bx90stYRX65aA3HRYW3eo8EL
+4y4+ppizueX3An9g88liKKM/BUuYI9qnrfd7dVLyFONrAgMBAAGjITAfMB0GA1Ud
+DgQWBBSf94jmG7aFyKSFnsWHOfe0294ogjANBgkqhkiG9w0BAQsFAAOCAgEAISH8
+BVtMbY9jyV3DmWLeXoSgunCSm9FKMSFGvvPHUaNhvvYddAiYYZ2UJryR1U8Mqv2I
+ehEOhZcwOi1Bz6gu4Pv0Qrz1sbBUd/f2jFJb77z2tNrUKPQUiW4nN6EhxW4RmraI
+LtN8RaQPmI6ZYXpz8i8n/AIpq2GsfK8bYNhTE4efOWf3p70oGrQpkADOSepcs5Es
+EXy3xPLGaduQn1Pj5QAXQKhxZ2JQS102R7dKOyClomp7ZM3yzmngpFmC21QWoXG1
+BaOfs3y7y1gJs5rH1gzjhay9CvzgIe6FdS1KD946bS+sp1NF55qiz0zwLEi0ZDnS
+mn1jYuzdF2C3CFtjgLRQmz+3pDTu3adai7HcDbUdCutOadBbJM8ikRQkKH/1ggNh
+94l7bT2hflTRCw2AXanWkT9mH5XPGAGuzImfMdGYCpxjOJLGQROoczHOKrLwwjdm
+ig9v5BXdJk+DA6QowvgvCwK+rrbwf8j68CJv8njp/1I+mek314R8UNu26wrWu0Yd
+NPvCXAtYPPrywCEPhUkaHI/63uP4OY6LyJDJb4j5gK5htnyI7nN1yJmIxLdrbCCi
+BUceEk3rhRArO/0iqhsQgHNj3K95DzQmNENAQrnxamw2tHkuC6j7KcPFCOLbV+n9
+7bFbeEUk2LVtFp2ZwdzzHAMwer4zQBhxOX5C0go=
+-----END CERTIFICATE-----
diff --git a/apex/manifest.json b/apex/manifest.json
new file mode 100644
index 0000000000..e5f06386a2
--- /dev/null
+++ b/apex/manifest.json
@@ -0,0 +1,7 @@
+{
+ "name": "com.android.bt",
+
+ // Placeholder module version to be replaced during build.
+ // Do not change!
+ "version": 0
+}
diff --git a/flags/Android.bp b/flags/Android.bp
index 63f4903b18..f43322d4ed 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -13,7 +13,6 @@ aconfig_declarations {
"a2dp.aconfig",
"active_device_manager.aconfig",
"adapter.aconfig",
- "asha.aconfig",
"avrcp.aconfig",
"avrcp_controller.aconfig",
"bta_dm.aconfig",
@@ -34,7 +33,6 @@ aconfig_declarations {
"l2cap.aconfig",
"le_advertising.aconfig",
"leaudio.aconfig",
- "map.aconfig",
"mapclient.aconfig",
"mcp.aconfig",
"metric.aconfig",
diff --git a/flags/BUILD.gn b/flags/BUILD.gn
index 773f237870..6c7185a24a 100644
--- a/flags/BUILD.gn
+++ b/flags/BUILD.gn
@@ -6,7 +6,6 @@ aconfig("bluetooth_flags_c_lib") {
"a2dp.aconfig",
"active_device_manager.aconfig",
"adapter.aconfig",
- "asha.aconfig",
"avrcp.aconfig",
"avrcp_controller.aconfig",
"bta_dm.aconfig",
@@ -27,7 +26,6 @@ aconfig("bluetooth_flags_c_lib") {
"l2cap.aconfig",
"le_advertising.aconfig",
"leaudio.aconfig",
- "map.aconfig",
"mapclient.aconfig",
"mcp.aconfig",
"metric.aconfig",
diff --git a/flags/a2dp.aconfig b/flags/a2dp.aconfig
index 25686f0c34..e6275bf010 100644
--- a/flags/a2dp.aconfig
+++ b/flags/a2dp.aconfig
@@ -2,26 +2,6 @@ package: "com.android.bluetooth.flags"
container: "com.android.btservices"
flag {
- name: "a2dp_service_looper"
- namespace: "bluetooth"
- description: "Inject looper into A2dpService"
- bug: "337348333"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "avdtp_error_codes"
- namespace: "bluetooth"
- description: "Use compliant error codes in AVDTP responses"
- bug: "338139069"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "bta_av_use_peer_codec"
namespace: "bluetooth"
description: "Deprecate bta av codec state"
@@ -52,16 +32,6 @@ flag {
}
flag {
- name: "a2dp_check_lea_iso_channel"
- namespace: "bluetooth"
- description: "Prevent A2DP stream from starting when LEA ISO channels are in use"
- bug: "346475618"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "a2dp_variable_aac_capability"
namespace: "bluetooth"
description: "Enable AAC 48 kHz sampling rate for sink devices in the allow list"
@@ -69,26 +39,6 @@ flag {
}
flag {
- name: "stop_on_offload_fail"
- namespace: "bluetooth"
- description: "Stop instead of disconnecting AVDT when offload fails"
- bug: "345709100"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "a2dp_aidl_encoding_interval"
- namespace: "bluetooth"
- description: "Configure the data interval in audio BT HAL's PcmConfig"
- bug: "347781402"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "av_stream_reconfigure_fix"
namespace: "bluetooth"
description: "Handle AVDT stream reconfiguration in an event"
@@ -99,16 +49,6 @@ flag {
}
flag {
- name: "avdt_discover_seps_as_acceptor"
- namespace: "bluetooth"
- description: "Discover stream end points when in acceptor role."
- bug: "351158317"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "avdt_prioritize_mandatory_codec"
namespace: "bluetooth"
description: "Reject remote peer HD codec configuration if mandatory codec is preferred in the stack"
@@ -129,16 +69,6 @@ flag {
}
flag {
- name: "a2dp_fix_codec_type_in_java"
- namespace: "bluetooth"
- description: "Mask out codec IDs such that they properly reflect unsigned value"
- bug: "361742051"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "fix_avdt_rconfig_not_setting_l2cap"
namespace: "bluetooth"
description: "Set L2CAP flushable and high priority after A2DP reconfigure"
@@ -185,3 +115,33 @@ flag {
is_exported: true
bug: "380118954"
}
+
+flag {
+ name: "a2dp_cleanup_on_remove_device"
+ namespace: "bluetooth"
+ description: "Always remove A2DP state machine when device is removed"
+ bug: "381313622"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "avdt_handle_signaling_on_peer_failure"
+ namespace: "bluetooth"
+ description: "Abort AVDTP on failed connection as the acceptor and retry as the initiator"
+ bug: "381388684"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "a2dp_sm_ignore_connect_events_in_connecting_state"
+ namespace: "bluetooth"
+ description: "When received CONNECT event in Connecting state, with no prior DISCONNECT - ignore the event"
+ bug: "383576378"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/flags/asha.aconfig b/flags/asha.aconfig
deleted file mode 100644
index ec130c0cfd..0000000000
--- a/flags/asha.aconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-package: "com.android.bluetooth.flags"
-container: "com.android.btservices"
-
-flag {
- name: "asha_encrypted_l2c_coc"
- namespace: "bluetooth"
- description: "Request encryption in LE CoC channel creation"
- bug: "348505552"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
diff --git a/flags/avrcp.aconfig b/flags/avrcp.aconfig
index 1c50da0949..5e806efb11 100644
--- a/flags/avrcp.aconfig
+++ b/flags/avrcp.aconfig
@@ -12,16 +12,6 @@ flag {
}
flag {
- name: "avrcp_connect_a2dp_with_delay"
- namespace: "bluetooth"
- description: "When peer device connects AVRCP but not A2DP we initiate A2DP connection after some time delay"
- bug: "328406945"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "browsing_refactor"
namespace: "bluetooth"
description: "Broadcast all players instead of BT player, remove MediaBrowser preload, support package modification"
diff --git a/flags/bta_dm.aconfig b/flags/bta_dm.aconfig
index e0ed3358b6..f35d562ebf 100644
--- a/flags/bta_dm.aconfig
+++ b/flags/bta_dm.aconfig
@@ -9,13 +9,6 @@ flag {
}
flag {
- name: "bt_system_context_report"
- namespace: "bluetooth"
- description: "Report Bluetooth system context through bta_ble_energy_info_cmpl"
- bug: "323083457"
-}
-
-flag {
name: "bta_dm_discover_both"
namespace: "bluetooth"
description: "perform both LE and Classic service discovery simulteanously on capable devices"
diff --git a/flags/framework.aconfig b/flags/framework.aconfig
index 934a3f6bb5..3a797af994 100644
--- a/flags/framework.aconfig
+++ b/flags/framework.aconfig
@@ -2,16 +2,6 @@ package: "com.android.bluetooth.flags"
container: "com.android.btservices"
flag {
- name: "override_context_to_specify_device_id"
- namespace: "bluetooth"
- description: "In Bluetooth Manager, override the context with createDeviceContext to pin a specific DeviceId"
- bug: "349657939"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "support_metadata_device_types_apis"
is_exported: true
namespace: "bluetooth"
diff --git a/flags/gap.aconfig b/flags/gap.aconfig
index 646e844a63..0ef4a7aa20 100644
--- a/flags/gap.aconfig
+++ b/flags/gap.aconfig
@@ -54,26 +54,6 @@ flag {
}
flag {
- name: "ble_check_data_length_on_legacy_advertising"
- namespace: "bluetooth"
- description: "Add data length checks for legacy advertising"
- bug: "329011868"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "ble_gatt_server_use_address_type_in_connection"
- namespace: "bluetooth"
- description: "Use address type when initiating connection from BluetoothGattServer"
- bug: "331147673"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "scan_record_manufacturer_data_merge"
namespace: "bluetooth"
description: "If a scan record has multiple datas under same manufacturer id, merge the values"
@@ -94,26 +74,6 @@ flag {
}
flag {
- name: "gatt_rediscover_on_canceled"
- namespace: "bluetooth"
- description: "Re-initiate discovery if the previous discovery is canceled for multiple GATT clients"
- bug: "335082571"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "le_scan_use_uid_for_importance"
- namespace: "bluetooth"
- description: "Use uid instead of the first package name for fetching the importance of clients"
- bug: "336965663"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "sec_dont_clear_keys_on_encryption_err"
namespace: "bluetooth"
description: "Do not clear security record on encryption error"
@@ -124,16 +84,6 @@ flag {
}
flag {
- name: "le_scan_use_address_type"
- namespace: "bluetooth"
- description: "Fix an issue that le scanner omits address type for MATCH_FIRST scan"
- bug: "342127181"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "gatt_client_dynamic_allocation"
namespace: "bluetooth"
description: "Allocate GATT clients in heap to unlimit the number of clients"
@@ -301,3 +251,33 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "configure_scan_on_resume"
+ namespace: "bluetooth"
+ description: "Configure scan paramters when start scanning from onResume"
+ bug: "383436218"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "unregister_gatt_client_disconnected"
+ namespace: "bluetooth"
+ description: "Unregister gatt client when disconneted to prevent client leaks"
+ bug: "380388092"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "fix_execute_write_no_pending"
+ namespace: "bluetooth"
+ description: "Send ATT_EXECUTE_WRITE_RSP when no pending write requests"
+ bug: "385118069"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/gatt.aconfig b/flags/gatt.aconfig
index 99b0305291..55e5b27077 100644
--- a/flags/gatt.aconfig
+++ b/flags/gatt.aconfig
@@ -10,3 +10,11 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "le_subrate_api"
+ namespace: "bluetooth"
+ description: "New API to control LE subrate parameters"
+ bug: "384794418"
+ is_exported: true
+}
diff --git a/flags/leaudio.aconfig b/flags/leaudio.aconfig
index ea5c23af22..a4eda31433 100644
--- a/flags/leaudio.aconfig
+++ b/flags/leaudio.aconfig
@@ -32,20 +32,6 @@ flag {
}
flag {
- name: "asymmetric_phy_for_unidirectional_cis"
- namespace: "bluetooth"
- description: "Apply asymetric PHY setting for unidirectional CIS"
- bug: "314176433"
-}
-
-flag {
- name: "leaudio_hal_client_asrc"
- namespace: "bluetooth"
- description: "Sync audio stream with the bluetooth link clock"
- bug: "312273987"
-}
-
-flag {
name: "metadata_api_inactive_audio_device_upon_connection"
is_exported: true
namespace: "bluetooth"
@@ -204,16 +190,6 @@ flag {
}
flag {
- name: "leaudio_call_start_scan_directly"
- namespace: "bluetooth"
- description: "Calling the framework is working only when we are expecting IPC. This will call the underlying implementation directly"
- bug: "348562830"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "leaudio_no_context_validate_streaming_request"
namespace: "bluetooth"
description: "Request streaming would be send without available cotext validation"
@@ -224,16 +200,6 @@ flag {
}
flag {
- name: "leaudio_synchronize_start"
- namespace: "bluetooth"
- description: "Do not post on main looper when starting le_audio"
- bug: "341385684"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "headtracker_codec_capability"
namespace: "bluetooth"
description: "Use Android Headtracker codec capabilities"
@@ -461,4 +427,34 @@ flag {
namespace: "bluetooth"
description: "Add OPUS codec type"
bug: "380029892"
-} \ No newline at end of file
+}
+
+flag {
+ name: "leaudio_broadcast_receive_state_processing_refactor"
+ namespace: "bluetooth"
+ description: "Fix parsing empty receive states and refactor its processing"
+ bug: "380231464"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "dsa_hw_transparent_codec"
+ namespace: "bluetooth"
+ description: "Use trasparent codec for DSA hardware path"
+ bug: "382263607"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "leaudio_use_audio_recording_listener"
+ namespace: "bluetooth"
+ description: "Use Audio Recording listener instead of monitoring sink session"
+ bug: "381054654"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/map.aconfig b/flags/map.aconfig
deleted file mode 100644
index 205627b727..0000000000
--- a/flags/map.aconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-package: "com.android.bluetooth.flags"
-container: "com.android.btservices"
-
-flag {
- name: "map_limit_notification"
- namespace: "bluetooth"
- description: "Skip notyfing old messages in MAP"
- bug: "325863406"
-}
diff --git a/flags/opp.aconfig b/flags/opp.aconfig
index 6e32ab0b75..bd0f380c45 100644
--- a/flags/opp.aconfig
+++ b/flags/opp.aconfig
@@ -2,23 +2,6 @@ package: "com.android.bluetooth.flags"
container: "com.android.btservices"
flag {
- name: "opp_start_activity_directly_from_notification"
- namespace: "bluetooth"
- description: "Make OPP notification start activities directly from it, not via OppReceiver"
- bug: "319050411"
-}
-
-flag {
- name: "opp_fix_multiple_notifications_issues"
- namespace: "bluetooth"
- description: "Fix UI issues related to multiple OPP notifications"
- bug: "323096132"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "opp_ignore_content_observer_after_service_stop"
namespace: "bluetooth"
description: "When OppService.stop() is called, previously posted ContentObserver.onChange() should not run"
diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig
index 3a96c4d3b4..b60302f5d1 100644
--- a/flags/pairing.aconfig
+++ b/flags/pairing.aconfig
@@ -112,16 +112,6 @@ flag {
}
flag {
- name: "use_encrypt_req_for_av"
- namespace: "bluetooth"
- description: "Use encrypted link for AVDTP and AVCTP channel"
- bug: "357662929"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "donot_queue_dup_rnr"
namespace: "bluetooth"
description: "Avoid queueing second RNR as part of ssp process"
@@ -240,3 +230,23 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "bonded_device_smp_failure_handling"
+ namespace: "bluetooth"
+ description: "Don't remove bond on SMP failure for bonded devices in peripheral role"
+ bug: "385181815"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "peripheral_auth_req"
+ namespace: "bluetooth"
+ description: "Use appropriate authentication requirements for SMP security request in peripheral role"
+ bug: "385202199"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/security.aconfig b/flags/security.aconfig
index c014a2a16d..2bb69eac95 100644
--- a/flags/security.aconfig
+++ b/flags/security.aconfig
@@ -25,3 +25,22 @@ flag {
}
}
+flag {
+ name: "btsec_check_valid_discovery_database"
+ namespace: "bluetooth"
+ description: "Check for a valid discovery database before using it, and don't set up a discovery database for a new HF client if one has already been defined for it"
+ bug: "356201480"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "le_enc_on_reconnection"
+ namespace: "bluetooth"
+ description: "Encrypt LE link on reconnection with bonded devices"
+ bug: "356201480"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/service_discovery.aconfig b/flags/service_discovery.aconfig
index 9ffc86a138..f5569086b9 100644
--- a/flags/service_discovery.aconfig
+++ b/flags/service_discovery.aconfig
@@ -10,3 +10,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "separate_service_storage"
+ namespace: "bluetooth"
+ description: "Store LE and Classic services separately"
+ bug: "382015666"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/sockets.aconfig b/flags/sockets.aconfig
index 5f00813a8b..688d27323c 100644
--- a/flags/sockets.aconfig
+++ b/flags/sockets.aconfig
@@ -62,3 +62,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "fix_buf_len_check_for_first_k_frame"
+ namespace: "bluetooth"
+ description: "Fix L2cap buffer length check against MPS for the first k-frame"
+ bug: "386382446"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/system_service.aconfig b/flags/system_service.aconfig
index 73f30611a6..fba0792eca 100644
--- a/flags/system_service.aconfig
+++ b/flags/system_service.aconfig
@@ -52,26 +52,6 @@ flag {
}
flag {
- name: "respect_ble_scan_setting"
- namespace: "bluetooth"
- description: "No longer allow BLE_ON mode when the settings is explicitly disable"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
- bug: "341783936"
-}
-
-flag {
- name: "ble_scan_setting_does_not_disconnect_if_bt_on"
- namespace: "bluetooth"
- description: "Stop calling unregAllGattClient when toggling the ble scan setting and bluetooth is ON"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
- bug: "379166793"
-}
-
-flag {
name: "system_server_messenger"
namespace: "bluetooth"
description: "Replace binder call to the system server with a Messenger to enforce thread safety"
diff --git a/flags/vcp.aconfig b/flags/vcp.aconfig
index bdc00477c7..43d5ec4c1c 100644
--- a/flags/vcp.aconfig
+++ b/flags/vcp.aconfig
@@ -7,3 +7,13 @@ flag {
description: "Allow muting/unmuting the remote device"
bug: "318775507"
}
+
+flag {
+ name: "vcp_device_volume_api_improvements"
+ namespace: "bluetooth"
+ description: "Refactor Device Volume API for generic usage"
+ bug: "381507732"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/floss/pandora/floss/qa_client.py b/floss/pandora/floss/qa_client.py
index 4fb7c99eb4..2e71fd526c 100644
--- a/floss/pandora/floss/qa_client.py
+++ b/floss/pandora/floss/qa_client.py
@@ -81,6 +81,14 @@ class BluetoothQACallbacks:
"""
pass
+ def on_send_hid_virtual_unplug_completed(self, status):
+ """Called when send hid virtual unplug completed.
+
+ Args:
+ status: BtStatus.
+ """
+ pass
+
class FlossQAClient(BluetoothQACallbacks):
"""Handles method calls to and callbacks from the QA interface."""
@@ -187,6 +195,15 @@ class FlossQAClient(BluetoothQACallbacks):
for observer in self.observers.values():
observer.on_send_hid_data_completed(status)
+ def OnSendHIDVirtualUnplugComplete(self, status):
+ """Handles send HID virtual unplug complete callback.
+
+ Args:
+ status: BtStatus.
+ """
+ for observer in self.observers.values():
+ observer.on_send_hid_virtual_unplug_completed(status)
+
def __init__(self, bus, hci):
"""Constructs the client.
@@ -269,6 +286,15 @@ class FlossQAClient(BluetoothQACallbacks):
"""
logging.debug('on_send_hid_data_completed: status: %s', status)
+ @utils.glib_callback()
+ def on_send_hid_data_completed(self, status):
+ """Handles send HID virtual unplug completed callback.
+
+ Args:
+ status: BtStatus.
+ """
+ logging.debug('on_send_hid_virtual_unplug_completed: status: %s', status)
+
@utils.glib_call(False)
def has_proxy(self):
"""Checks whether QA proxy can be acquired."""
diff --git a/framework/Android.bp b/framework/Android.bp
index e6a14f79f9..6e5dafc3e1 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -78,7 +78,7 @@ java_sdk_library {
"//packages/modules/Bluetooth/service",
"//packages/services/Car/car-builtin-lib",
// TODO(240720385)
- "//packages/services/Car/tests/carservice_unit_test",
+ "//packages/services/Car/tests/CarBuiltinLibUnitTest",
":__subpackages__",
],
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 8bec61f117..a9bc28a28a 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -52,7 +52,7 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
- method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingSocketSettings(@NonNull android.bluetooth.BluetoothSocketSettings) throws java.io.IOException;
+ method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true) public android.bluetooth.BluetoothServerSocket listenUsingSocketSettings(@NonNull android.bluetooth.BluetoothSocketSettings) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setName(String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startDiscovery();
method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
@@ -541,6 +541,7 @@ package android.bluetooth {
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getAlias();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothClass getBluetoothClass();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getBondState();
+ method @FlaggedApi("com.android.bluetooth.flags.identity_address_type_api") @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothDevice.BluetoothAddress getIdentityAddressWithType();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getType();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelUuid[] getUuids();
@@ -607,6 +608,15 @@ package android.bluetooth {
field public static final int TRANSPORT_LE = 2; // 0x2
}
+ @FlaggedApi("com.android.bluetooth.flags.identity_address_type_api") public static final class BluetoothDevice.BluetoothAddress implements android.os.Parcelable {
+ ctor public BluetoothDevice.BluetoothAddress(@Nullable String, int);
+ method public int describeContents();
+ method @Nullable public String getAddress();
+ method public int getAddressType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothDevice.BluetoothAddress> CREATOR;
+ }
+
public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite();
method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite(android.bluetooth.BluetoothDevice);
@@ -1084,7 +1094,7 @@ package android.bluetooth {
public final class BluetoothSocket implements java.io.Closeable {
method public void close() throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void connect() throws java.io.IOException;
+ method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true) public void connect() throws java.io.IOException;
method public int getConnectionType();
method public java.io.InputStream getInputStream() throws java.io.IOException;
method public int getMaxReceivePacketSize();
@@ -1122,7 +1132,7 @@ package android.bluetooth {
field public static final int SOCKET_CLOSED = 17; // 0x11
field public static final int SOCKET_CONNECTION_FAILURE = 18; // 0x12
field public static final int SOCKET_MANAGER_FAILURE = 16; // 0x10
- field @FlaggedApi("com.android.bluetooth.flags.unix_file_socket_creation_failure") public static final int UNIX_FILE_SOCKET_CREATION_FAILURE = 21; // 0x15
+ field public static final int UNIX_FILE_SOCKET_CREATION_FAILURE = 21; // 0x15
field public static final int UNSPECIFIED = 0; // 0x0
}
@@ -1232,7 +1242,7 @@ package android.bluetooth.le {
public final class AdvertisingSet {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void enableAdvertising(boolean, int, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true) public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 06f611fcaa..8368f676b8 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -127,7 +127,9 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isAutoOnSupported();
method public boolean isBleScanAlwaysAvailable();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isDistanceMeasurementSupported();
+ method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isLeCocSocketOffloadSupported();
method public boolean isLeEnabled();
+ method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isRfcommSocketOffloadSupported();
method @NonNull public static String nameForState(int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int notifyActiveDeviceChangeApplied(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean registerBluetoothConnectionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.BluetoothConnectionCallback);
@@ -1152,6 +1154,25 @@ package android.bluetooth {
public final class BluetoothSocket implements java.io.Closeable {
method @FlaggedApi("com.android.bluetooth.flags.bt_socket_api_l2cap_cid") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getL2capLocalChannelId() throws java.io.IOException;
method @FlaggedApi("com.android.bluetooth.flags.bt_socket_api_l2cap_cid") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getL2capRemoteChannelId() throws java.io.IOException;
+ method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") public long getSocketId() throws java.io.IOException;
+ }
+
+ @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") public final class BluetoothSocketSettings {
+ method public int getDataPath();
+ method public long getEndpointId();
+ method public long getHubId();
+ method public int getRequestedMaximumPacketSize();
+ method @NonNull public String getSocketName();
+ field public static final int DATA_PATH_HARDWARE_OFFLOAD = 1; // 0x1
+ field public static final int DATA_PATH_NO_OFFLOAD = 0; // 0x0
+ }
+
+ @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") public static final class BluetoothSocketSettings.Builder {
+ method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setDataPath(int);
+ method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setEndpointId(long);
+ method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setHubId(long);
+ method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setRequestedMaximumPacketSize(int);
+ method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setSocketName(@NonNull String);
}
public final class BluetoothStatusCodes {
diff --git a/framework/jarjar-rules.txt b/framework/jarjar-rules.txt
index 93ec44901c..e32ce85165 100644
--- a/framework/jarjar-rules.txt
+++ b/framework/jarjar-rules.txt
@@ -12,4 +12,14 @@ rule com.android.internal.util.** com.android.bluetooth.jarjar.@0
rule com.android.modules.expresslog.** com.android.bluetooth.jarjar.@0
rule com.android.bluetooth.flags.** com.android.bluetooth.jarjar.@0
rule bluetooth.constants.** com.android.bluetooth.jarjar.@0
-rule android.media.audio.Flags com.android.bluetooth.jarjar.audio.Flags
+rule android.os.Flags com.android.bluetooth.jarjar.@0
+rule android.os.CustomFeatureFlags com.android.bluetooth.jarjar.@0
+rule android.os.FeatureFlagsImpl com.android.bluetooth.jarjar.@0
+rule android.os.FakeFeatureFlagsImpl com.android.bluetooth.jarjar.@0
+rule android.os.FeatureFlags com.android.bluetooth.jarjar.@0
+
+rule android.media.audio.Flags com.android.bluetooth.jarjar.@0
+rule android.media.audio.CustomFeatureFlags com.android.bluetooth.jarjar.@0
+rule android.media.audio.FeatureFlagsImpl com.android.bluetooth.jarjar.@0
+rule android.media.audio.FakeFeatureFlagsImpl com.android.bluetooth.jarjar.@0
+rule android.media.audio.FeatureFlags com.android.bluetooth.jarjar.@0
diff --git a/framework/java/android/bluetooth/AudioInputControl.java b/framework/java/android/bluetooth/AudioInputControl.java
index a8e30328f4..b39458b15f 100644
--- a/framework/java/android/bluetooth/AudioInputControl.java
+++ b/framework/java/android/bluetooth/AudioInputControl.java
@@ -432,6 +432,8 @@ public class AudioInputControl {
/**
* Gets the minimum value for the gain setting.
*
+ * <p>The value return is relative to {@link #getGainSettingUnit} in 0.1 decibel units.
+ *
* @return The minimum Gain Setting as defined in AICS 1.0 - 3.2.2.
*/
@RequiresBluetoothConnectPermission
@@ -446,6 +448,8 @@ public class AudioInputControl {
/**
* Gets the maximum value for the gain setting.
*
+ * <p>The value return is relative to {@link #getGainSettingUnit} in 0.1 decibel units.
+ *
* @return The maximum Gain Setting as defined in AICS 1.0 - 3.2.3.
*/
@RequiresBluetoothConnectPermission
@@ -544,6 +548,8 @@ public class AudioInputControl {
* <p>Register an {@link AudioInputCallback} to be notified via {@link
* AudioInputCallback#onGainSettingChanged} when the gain setting changes.
*
+ * <p>The value return is relative to {@link #getGainSettingUnit} in 0.1 decibel units.
+ *
* @return The current gain setting as defined in AICS 1.0 - 2.2.1.1.
*/
@RequiresBluetoothConnectPermission
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java
index 2d26bf3e1d..2ffc178e6e 100644
--- a/framework/java/android/bluetooth/BluetoothAdapter.java
+++ b/framework/java/android/bluetooth/BluetoothAdapter.java
@@ -4564,6 +4564,14 @@ public final class BluetoothAdapter {
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
* {@link BluetoothServerSocket}.
*
+ * <p>Use {@link BluetoothDevice#createUsingSocketSettings(BluetoothSocketSettings)} to connect
+ * to this server socket from another Android device using the L2cap protocol/service
+ * multiplexer(PSM) value or the RFCOMM service UUID as input.
+ *
+ * <p>This API requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission
+ * only when {@code settings.getDataPath()} is different from {@link
+ * BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
+ *
* <p>This API supports {@link BluetoothSocket#TYPE_RFCOMM} and {{@link BluetoothSocket#TYPE_LE}
* only, which can be set using {@link BluetoothSocketSettings#setSocketType()}.
* <li>For `BluetoothSocket.TYPE_RFCOMM`: The RFCOMM UUID must be provided using {@link
@@ -4574,10 +4582,6 @@ public final class BluetoothAdapter {
* application exits unexpectedly. The mechanism for disclosing the PSM value to the client
* is application-defined.
*
- * <p>Use {@link BluetoothDevice#createUsingSocketSettings(BluetoothSocketSettings)} to
- * connect to this server socket from another Android device using the L2cap
- * protocol/service multiplexer(PSM) value or the RFCOMM service UUID as input.
- *
* @param settings Bluetooth socket settings {@link BluetoothSocketSettings}.
* @return a {@link BluetoothServerSocket}
* @throws IllegalArgumentException if BluetoothSocket#TYPE_RFCOMM socket is requested with no
@@ -4586,7 +4590,9 @@ public final class BluetoothAdapter {
* Connection-oriented Channel (CoC).
*/
@RequiresBluetoothConnectPermission
- @RequiresPermission(BLUETOOTH_CONNECT)
+ @RequiresPermission(
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
@FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
public @NonNull BluetoothServerSocket listenUsingSocketSettings(
@NonNull BluetoothSocketSettings settings) throws IOException {
@@ -4597,24 +4603,64 @@ public final class BluetoothAdapter {
if (settings.getRfcommUuid() == null) {
throw new IllegalArgumentException("RFCOMM server missing UUID");
}
- return createNewRfcommSocketAndRecord(
- settings.getRfcommServiceName(),
- settings.getRfcommUuid(),
- settings.isAuthenticationRequired(),
- settings.isEncryptionRequired());
+ if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ socket =
+ new BluetoothServerSocket(
+ settings.getSocketType(),
+ settings.isAuthenticationRequired(),
+ settings.isEncryptionRequired(),
+ new ParcelUuid(settings.getRfcommUuid()));
+ } else {
+ socket =
+ new BluetoothServerSocket(
+ settings.getSocketType(),
+ settings.isAuthenticationRequired(),
+ settings.isEncryptionRequired(),
+ -1,
+ new ParcelUuid(settings.getRfcommUuid()),
+ false,
+ false,
+ settings.getDataPath(),
+ settings.getSocketName(),
+ settings.getHubId(),
+ settings.getEndpointId(),
+ settings.getRequestedMaximumPacketSize());
+ }
+ socket.setServiceName(settings.getRfcommServiceName());
} else if (type == BluetoothSocket.TYPE_LE) {
- socket =
- new BluetoothServerSocket(
- settings.getSocketType(),
- settings.isAuthenticationRequired(),
- settings.isEncryptionRequired(),
- SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
- false,
- false);
+ if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ socket =
+ new BluetoothServerSocket(
+ settings.getSocketType(),
+ settings.isAuthenticationRequired(),
+ settings.isEncryptionRequired(),
+ SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
+ false,
+ false);
+ } else {
+ socket =
+ new BluetoothServerSocket(
+ settings.getSocketType(),
+ settings.isAuthenticationRequired(),
+ settings.isEncryptionRequired(),
+ SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
+ null,
+ false,
+ false,
+ settings.getDataPath(),
+ settings.getSocketName(),
+ settings.getHubId(),
+ settings.getEndpointId(),
+ settings.getRequestedMaximumPacketSize());
+ }
} else {
- throw new IOException("Error: Invalid socket type: " + type);
+ throw new IllegalArgumentException("Error: Invalid socket type: " + type);
}
- int errno = socket.mSocket.bindListen();
+ int errno;
+ errno =
+ (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD)
+ ? socket.mSocket.bindListen()
+ : socket.mSocket.bindListenWithOffload();
if (errno != 0) {
throw new IOException("Error: " + errno);
}
@@ -5916,4 +5962,98 @@ public final class BluetoothAdapter {
mServiceLock.readLock().unlock();
}
}
+
+ /**
+ * Returns whether LE CoC socket hardware offload is supported.
+ *
+ * <p>Bluetooth socket hardware offload allows the system to handle Bluetooth communication on a
+ * low-power processor, improving efficiency and reducing power consumption. This is achieved by
+ * providing channel information of an already connected {@link BluetoothSocket} to offload
+ * endpoints (e.g., offload stacks and applications). The offload stack can then decode received
+ * packets and pass them to the appropriate offload application without waking up the main
+ * application processor. This API allows offload endpoints to utilize Bluetooth sockets while
+ * the host stack retains control over the connection.
+ *
+ * <p>To configure a socket for hardware offload, use the following {@link
+ * BluetoothSocketSettings} methods:
+ *
+ * <ul>
+ * <li>{@link BluetoothSocketSettings#setDataPath(int)} with {@link
+ * BluetoothSocketSettings#DATA_PATH_HARDWARE_OFFLOAD}
+ * <li>{@link BluetoothSocketSettings#setHubId(long)}
+ * <li>{@link BluetoothSocketSettings#setEndpointId(long)}
+ * </ul>
+ *
+ * <p>This functionality is provided as a System API because only OEM specific system
+ * applications can be offloaded as endpoints in the low-power processor.
+ *
+ * @return {@code true} if LE CoC socket hardware offload is supported, {@code false} otherwise.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
+ @RequiresPermission(BLUETOOTH_PRIVILEGED)
+ public boolean isLeCocSocketOffloadSupported() {
+ if (!isEnabled()) {
+ return false;
+ }
+ mServiceLock.readLock().lock();
+ try {
+ if (mService != null) {
+ return mService.isLeCocSocketOffloadSupported(mAttributionSource);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether RFCOMM socket hardware offload is supported.
+ *
+ * <p>Bluetooth socket hardware offload allows the system to handle Bluetooth communication on a
+ * low-power processor, improving efficiency and reducing power consumption. This is achieved by
+ * providing channel information of an already connected {@link BluetoothSocket} to offload
+ * endpoints (e.g., offload stacks and applications). The offload stack can then decode received
+ * packets and pass them to the appropriate offload application without waking up the main
+ * application processor. This API allows offload endpoints to utilize Bluetooth sockets while
+ * the host stack retains control over the connection.
+ *
+ * <p>To configure a socket for hardware offload, use the following {@link
+ * BluetoothSocketSettings} methods:
+ *
+ * <ul>
+ * <li>{@link BluetoothSocketSettings#setDataPath(int)} with {@link
+ * BluetoothSocketSettings#DATA_PATH_HARDWARE_OFFLOAD}
+ * <li>{@link BluetoothSocketSettings#setHubId(long)}
+ * <li>{@link BluetoothSocketSettings#setEndpointId(long)}
+ * </ul>
+ *
+ * <p>This functionality is provided as a System API because only OEM specific system
+ * applications can be offloaded as endpoints in the low-power processor.
+ *
+ * @return {@code true} if RFCOMM socket hardware offload is supported, {@code false} otherwise.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
+ @RequiresPermission(BLUETOOTH_PRIVILEGED)
+ public boolean isRfcommSocketOffloadSupported() {
+ if (!isEnabled()) {
+ return false;
+ }
+ mServiceLock.readLock().lock();
+ try {
+ if (mService != null) {
+ return mService.isRfcommSocketOffloadSupported(mAttributionSource);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
+ }
}
diff --git a/framework/java/android/bluetooth/BluetoothCodecType.java b/framework/java/android/bluetooth/BluetoothCodecType.java
index 6bd5045c56..54547fe3f5 100644
--- a/framework/java/android/bluetooth/BluetoothCodecType.java
+++ b/framework/java/android/bluetooth/BluetoothCodecType.java
@@ -37,11 +37,7 @@ public final class BluetoothCodecType implements Parcelable {
private BluetoothCodecType(Parcel in) {
mNativeCodecType = in.readInt();
- if (Flags.a2dpFixCodecTypeInJava()) {
- mCodecId = in.readLong() & 0xFFFFFFFFL;
- } else {
- mCodecId = in.readLong();
- }
+ mCodecId = in.readLong() & 0xFFFFFFFFL;
mCodecName = in.readString();
}
@@ -75,11 +71,7 @@ public final class BluetoothCodecType implements Parcelable {
*/
private BluetoothCodecType(@BluetoothCodecConfig.SourceCodecType int codecType, long codecId) {
mNativeCodecType = codecType;
- if (Flags.a2dpFixCodecTypeInJava()) {
- mCodecId = codecId & 0xFFFFFFFFL;
- } else {
- mCodecId = codecId;
- }
+ mCodecId = codecId & 0xFFFFFFFFL;
mCodecName = BluetoothCodecConfig.getCodecName(codecType);
}
@@ -94,11 +86,7 @@ public final class BluetoothCodecType implements Parcelable {
@SystemApi
public BluetoothCodecType(int codecType, long codecId, @NonNull String codecName) {
mNativeCodecType = codecType;
- if (Flags.a2dpFixCodecTypeInJava()) {
- mCodecId = codecId & 0xFFFFFFFFL;
- } else {
- mCodecId = codecId;
- }
+ mCodecId = codecId & 0xFFFFFFFFL;
mCodecName = codecName;
}
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index edccc5e027..58dd3ba1da 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -1726,6 +1726,33 @@ public final class BluetoothDevice implements Parcelable, Attributable {
}
/**
+ * Returns the identity address and identity address type of this BluetoothDevice.
+ *
+ * @return a {@link BluetoothAddress} containing identity address and identity address type. If
+ * Bluetooth is not enabled or identity address type is not available, it will return a
+ * {@link BluetoothAddress} containing {@link #ADDRESS_TYPE_UNKNOWN} device for the identity
+ * address type.
+ */
+ @FlaggedApi(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
+ @NonNull
+ public BluetoothAddress getIdentityAddressWithType() {
+ if (DBG) log("getIdentityAddressWithType()");
+ final IBluetooth service = getService();
+ if (service == null || !isBluetoothEnabled()) {
+ Log.e(TAG, "BT not enabled. Cannot get identity address with type");
+ } else {
+ try {
+ return service.getIdentityAddressWithType(mAddress);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ }
+ }
+ return new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN);
+ }
+
+ /**
* Get the friendly Bluetooth name of the remote device.
*
* <p>The local adapter will automatically retrieve remote names when performing a device scan,
@@ -3339,13 +3366,30 @@ public final class BluetoothDevice implements Parcelable, Attributable {
throw new IllegalArgumentException("Invalid PSM/Channel value: " + psm);
}
}
- return new BluetoothSocket(
- this,
- settings.getSocketType(),
- settings.isAuthenticationRequired(),
- settings.isEncryptionRequired(),
- psm,
- uuid);
+ if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ return new BluetoothSocket(
+ this,
+ settings.getSocketType(),
+ settings.isAuthenticationRequired(),
+ settings.isEncryptionRequired(),
+ psm,
+ uuid);
+ } else {
+ return new BluetoothSocket(
+ this,
+ settings.getSocketType(),
+ settings.isAuthenticationRequired(),
+ settings.isEncryptionRequired(),
+ psm,
+ uuid,
+ false,
+ false,
+ settings.getDataPath(),
+ settings.getSocketName(),
+ settings.getHubId(),
+ settings.getEndpointId(),
+ settings.getRequestedMaximumPacketSize());
+ }
}
/**
@@ -3748,4 +3792,66 @@ public final class BluetoothDevice implements Parcelable, Attributable {
private static void log(String msg) {
Log.d(TAG, msg);
}
+
+ /** A data class for Bluetooth address and address type. */
+ @FlaggedApi(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API)
+ public static final class BluetoothAddress implements Parcelable {
+ private final @Nullable String mAddress;
+ private final @AddressType int mAddressType;
+
+ public BluetoothAddress(@Nullable String address, @AddressType int addressType) {
+ mAddress = address;
+ mAddressType = addressType;
+ }
+
+ /**
+ * Returns the address of this {@link BluetoothAddress}.
+ *
+ * <p>For example, "00:11:22:AA:BB:CC".
+ *
+ * @return Bluetooth address as string
+ */
+ @Nullable
+ public String getAddress() {
+ return mAddress;
+ }
+
+ /**
+ * Returns the address type of this {@link BluetoothAddress}, one of {@link
+ * #ADDRESS_TYPE_PUBLIC}, {@link #ADDRESS_TYPE_RANDOM}, or {@link #ADDRESS_TYPE_UNKNOWN}.
+ *
+ * @return Bluetooth address type
+ */
+ @AddressType
+ public int getAddressType() {
+ return mAddressType;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ BluetoothUtils.writeStringToParcel(out, mAddress);
+ out.writeInt(mAddressType);
+ }
+
+ private BluetoothAddress(@NonNull Parcel in) {
+ this(in.readString(), in.readInt());
+ }
+
+ /** {@link Parcelable.Creator} interface implementation. */
+ public static final @NonNull Parcelable.Creator<BluetoothAddress> CREATOR =
+ new Parcelable.Creator<BluetoothAddress>() {
+ public @NonNull BluetoothAddress createFromParcel(Parcel in) {
+ return new BluetoothAddress(in);
+ }
+
+ public @NonNull BluetoothAddress[] newArray(int size) {
+ return new BluetoothAddress[size];
+ }
+ };
+ }
}
diff --git a/framework/java/android/bluetooth/BluetoothGatt.java b/framework/java/android/bluetooth/BluetoothGatt.java
index e63b5987ac..e67d823c7e 100644
--- a/framework/java/android/bluetooth/BluetoothGatt.java
+++ b/framework/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,8 @@
package android.bluetooth;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+import static android.bluetooth.BluetoothUtils.logRemoteException;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -368,7 +370,8 @@ public final class BluetoothGatt implements BluetoothProfile {
+ (" status=" + status)
+ (" clientIf=" + clientIf)
+ (" connected=" + connected)
- + (" device=" + address));
+ + (" device="
+ + BluetoothUtils.toAnonymizedAddress(address)));
}
if (!address.equals(mDevice.getAddress())) {
return;
@@ -477,7 +480,7 @@ public final class BluetoothGatt implements BluetoothProfile {
Log.d(
TAG,
"onCharacteristicRead() -"
- + (" Device=" + address)
+ + (" Device=" + BluetoothUtils.toAnonymizedAddress(address))
+ (" handle=" + handle)
+ (" Status=" + status));
}
@@ -544,7 +547,7 @@ public final class BluetoothGatt implements BluetoothProfile {
Log.d(
TAG,
"onCharacteristicWrite() -"
- + (" Device=" + address)
+ + (" Device=" + BluetoothUtils.toAnonymizedAddress(address))
+ (" handle=" + handle)
+ (" Status=" + status));
}
@@ -817,7 +820,7 @@ public final class BluetoothGatt implements BluetoothProfile {
Log.d(
TAG,
"onReadRemoteRssi() -"
- + (" Device=" + address)
+ + (" Device=" + BluetoothUtils.toAnonymizedAddress(address))
+ (" rssi=" + rssi)
+ (" status=" + status));
}
@@ -847,7 +850,7 @@ public final class BluetoothGatt implements BluetoothProfile {
Log.d(
TAG,
"onConfigureMTU() -"
- + (" Device=" + address)
+ + (" Device=" + BluetoothUtils.toAnonymizedAddress(address))
+ (" mtu=" + mtu)
+ (" status=" + status));
}
@@ -879,7 +882,7 @@ public final class BluetoothGatt implements BluetoothProfile {
Log.d(
TAG,
"onConnectionUpdated() -"
- + (" Device=" + address)
+ + (" Device=" + BluetoothUtils.toAnonymizedAddress(address))
+ (" interval=" + interval)
+ (" latency=" + latency)
+ (" timeout=" + timeout)
@@ -914,7 +917,10 @@ public final class BluetoothGatt implements BluetoothProfile {
@Override
public void onServiceChanged(String address) {
if (DBG) {
- Log.d(TAG, "onServiceChanged() - Device=" + address);
+ Log.d(
+ TAG,
+ "onServiceChanged() - Device="
+ + BluetoothUtils.toAnonymizedAddress(address));
}
if (!address.equals(mDevice.getAddress())) {
@@ -949,7 +955,7 @@ public final class BluetoothGatt implements BluetoothProfile {
Log.d(
TAG,
"onSubrateChange() - "
- + (" Device=" + address)
+ + (" Device=" + BluetoothUtils.toAnonymizedAddress(address))
+ (" subrateFactor=" + subrateFactor)
+ (" latency=" + latency)
+ (" contNum=" + contNum)
@@ -2118,85 +2124,40 @@ public final class BluetoothGatt implements BluetoothProfile {
*
* <p>This function will send a LE subrate request to the remote device.
*
+ * <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 subrateMode Request a specific subrate mode.
* @throws IllegalArgumentException If the parameters are outside of their specified range.
* @return true, if the request is send to the Bluetooth stack.
* @hide
*/
@RequiresBluetoothConnectPermission
- @RequiresPermission(BLUETOOTH_CONNECT)
- public boolean requestSubrateMode(@SubrateRequestMode int subrateMode) {
+ @RequiresPermission(
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
+ public int requestSubrateMode(@SubrateRequestMode int subrateMode) {
if (subrateMode < SUBRATE_REQUEST_MODE_BALANCED
|| subrateMode > SUBRATE_REQUEST_MODE_LOW_POWER) {
throw new IllegalArgumentException("Subrate Mode not within valid range");
}
if (DBG) {
- Log.d(TAG, "requestsubrateMode() - subrateMode: " + subrateMode);
+ Log.d(TAG, "requestsubrateMode(" + subrateMode + ")");
}
if (mService == null || mClientIf == 0) {
- return false;
+ return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
}
try {
- mService.subrateModeRequest(
- mClientIf, mDevice.getAddress(), subrateMode, mAttributionSource);
+ return mService.subrateModeRequest(mClientIf, mDevice, subrateMode, mAttributionSource);
} catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
+ logRemoteException(TAG, e);
+ return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
}
- return true;
- }
-
- /**
- * Request a LE subrate request.
- *
- * <p>This function will send a LE subrate request to the remote device.
- *
- * @return true, if the request is send to the Bluetooth stack.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(BLUETOOTH_CONNECT)
- public boolean bleSubrateRequest(
- int subrateMin,
- int subrateMax,
- int maxLatency,
- int contNumber,
- int supervisionTimeout) {
- if (DBG) {
- Log.d(
- TAG,
- "bleSubrateRequest() - subrateMin="
- + subrateMin
- + " subrateMax="
- + (subrateMax)
- + " maxLatency= "
- + maxLatency
- + "contNumber="
- + contNumber
- + " supervisionTimeout="
- + supervisionTimeout);
- }
- if (mService == null || mClientIf == 0) {
- return false;
- }
-
- try {
- mService.leSubrateRequest(
- mClientIf,
- mDevice.getAddress(),
- subrateMin,
- subrateMax,
- maxLatency,
- contNumber,
- supervisionTimeout,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
- return true;
}
/**
diff --git a/framework/java/android/bluetooth/BluetoothGattServer.java b/framework/java/android/bluetooth/BluetoothGattServer.java
index 53b491e1b3..94bf7ae4c4 100644
--- a/framework/java/android/bluetooth/BluetoothGattServer.java
+++ b/framework/java/android/bluetooth/BluetoothGattServer.java
@@ -115,7 +115,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
+ " connected="
+ connected
+ " device="
- + address);
+ + BluetoothUtils.toAnonymizedAddress(address));
}
try {
mCallback.onConnectionStateChange(
@@ -305,7 +305,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
TAG,
"onExecuteWrite() - "
+ "device="
- + address
+ + BluetoothUtils.toAnonymizedAddress(address)
+ ", transId="
+ transId
+ "execWrite="
@@ -334,7 +334,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
TAG,
"onNotificationSent() - "
+ "device="
- + address
+ + BluetoothUtils.toAnonymizedAddress(address)
+ ", status="
+ status);
}
@@ -388,7 +388,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
TAG,
"onPhyUpdate() - "
+ "device="
- + address
+ + BluetoothUtils.toAnonymizedAddress(address)
+ ", txPHy="
+ txPhy
+ ", rxPHy="
@@ -417,7 +417,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
TAG,
"onPhyUpdate() - "
+ "device="
- + address
+ + BluetoothUtils.toAnonymizedAddress(address)
+ ", txPHy="
+ txPhy
+ ", rxPHy="
@@ -446,7 +446,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
Log.d(
TAG,
"onConnectionUpdated() - Device="
- + address
+ + BluetoothUtils.toAnonymizedAddress(address)
+ " interval="
+ interval
+ " latency="
diff --git a/framework/java/android/bluetooth/BluetoothManager.java b/framework/java/android/bluetooth/BluetoothManager.java
index 7f6a0e4e42..00522d4f89 100644
--- a/framework/java/android/bluetooth/BluetoothManager.java
+++ b/framework/java/android/bluetooth/BluetoothManager.java
@@ -60,7 +60,7 @@ public final class BluetoothManager {
/** @hide */
public BluetoothManager(Context context) {
- if (com.android.bluetooth.flags.Flags.overrideContextToSpecifyDeviceId() && isAtLeastU()) {
+ if (isAtLeastU()) {
// Pin the context DeviceId prevent the associated attribution source to be obsolete
// TODO: b/343739429 -- pass the context to BluetoothAdapter constructor instead
mContext = context.createDeviceContext(Context.DEVICE_ID_DEFAULT);
diff --git a/framework/java/android/bluetooth/BluetoothServerSocket.java b/framework/java/android/bluetooth/BluetoothServerSocket.java
index b1a0188626..f20a03d1cc 100644
--- a/framework/java/android/bluetooth/BluetoothServerSocket.java
+++ b/framework/java/android/bluetooth/BluetoothServerSocket.java
@@ -16,6 +16,7 @@
package android.bluetooth;
+import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Handler;
@@ -154,6 +155,60 @@ public final class BluetoothServerSocket implements Closeable {
}
/**
+ * Construct a socket for incoming connections.
+ *
+ * @param type type of socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param port remote port
+ * @param uuid uuid
+ * @param pitm enforce person-in-the-middle protection for authentication.
+ * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
+ * @param dataPath data path used for this socket
+ * @param socketName user-friendly name for this socket
+ * @param hubId ID of the hub to which the end point belongs
+ * @param endpointId ID of the endpoint within the hub that is associated with this socket
+ * @param maximumPacketSize The maximum size (in bytes) of a single data packet
+ * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
+ */
+ /*package*/ BluetoothServerSocket(
+ int type,
+ boolean auth,
+ boolean encrypt,
+ int port,
+ ParcelUuid uuid,
+ boolean pitm,
+ boolean min16DigitPin,
+ int dataPath,
+ @NonNull String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize)
+ throws IOException {
+ mSocketCreationTimeMillis = System.currentTimeMillis();
+ mType = type;
+ mChannel = port;
+ mSocket =
+ new BluetoothSocket(
+ type,
+ auth,
+ encrypt,
+ port,
+ uuid,
+ pitm,
+ min16DigitPin,
+ dataPath,
+ socketName,
+ hubId,
+ endpointId,
+ maximumPacketSize);
+ if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ mSocket.setExcludeSdp(true);
+ }
+ mSocketCreationLatencyMillis = System.currentTimeMillis() - mSocketCreationTimeMillis;
+ }
+
+ /**
* Block until a connection is established.
*
* <p>Returns a connected {@link BluetoothSocket} on successful connection.
diff --git a/framework/java/android/bluetooth/BluetoothSocket.java b/framework/java/android/bluetooth/BluetoothSocket.java
index 901407c00b..d33542e6d6 100644
--- a/framework/java/android/bluetooth/BluetoothSocket.java
+++ b/framework/java/android/bluetooth/BluetoothSocket.java
@@ -157,6 +157,8 @@ public final class BluetoothSocket implements Closeable {
/*package*/ static final int SEC_FLAG_AUTH_PITM = 1 << 3;
/*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4;
+ /*package*/ static final String DEFAULT_SOCKET_NAME = "default_name";
+
private final int mType; /* one of TYPE_RFCOMM etc */
private BluetoothDevice mDevice; /* remote device */
private String mAddress; /* remote address */
@@ -165,6 +167,11 @@ public final class BluetoothSocket implements Closeable {
private final BluetoothInputStream mInputStream;
private final BluetoothOutputStream mOutputStream;
private final ParcelUuid mUuid;
+ private final int mDataPath;
+ private final String mSocketName;
+ private final long mHubId;
+ private final long mEndpointId;
+ private final int mMaximumPacketSize;
/** when true no SPP SDP record will be created */
private boolean mExcludeSdp = false;
@@ -184,12 +191,15 @@ public final class BluetoothSocket implements Closeable {
@UnsupportedAppUsage private int mPort; /* RFCOMM channel or L2CAP psm */
private String mServiceName;
- private static final int SOCK_SIGNAL_SIZE = 36;
+ private static final int SOCK_CONNECTION_SIGNAL_SIZE = 44;
+ private static final long INVALID_SOCKET_ID = 0;
+ private static final int SOCK_ACCEPT_SIGNAL_SIZE = 4;
private ByteBuffer mL2capBuffer = null;
private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
private ParcelUuid mConnectionUuid;
+ private long mSocketId; // Socket ID in connected state.
private long mSocketCreationTimeNanos = 0;
private long mSocketCreationLatencyNanos = 0;
@@ -245,6 +255,41 @@ public final class BluetoothSocket implements Closeable {
boolean pitm,
boolean min16DigitPin)
throws IOException {
+ this(type, auth, encrypt, port, uuid, pitm, min16DigitPin, 0, DEFAULT_SOCKET_NAME, 0, 0, 0);
+ }
+
+ /**
+ * Construct a BluetoothSocket.
+ *
+ * @param type type of socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param port remote port
+ * @param uuid SDP uuid
+ * @param pitm enforce person-in-the-middle protection.
+ * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
+ * @param dataPath data path used for this socket
+ * @param socketName user-friendly name for this socket
+ * @param hubId ID of the hub to which the end point belongs
+ * @param endpointId ID of the endpoint within the hub that is associated with this socket
+ * @param maximumPacketSize The maximum size (in bytes) of a single data packet
+ * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
+ */
+ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
+ /*package*/ BluetoothSocket(
+ int type,
+ boolean auth,
+ boolean encrypt,
+ int port,
+ ParcelUuid uuid,
+ boolean pitm,
+ boolean min16DigitPin,
+ int dataPath,
+ @NonNull String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize)
+ throws IOException {
if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
mSocketCreationTimeNanos = System.nanoTime();
if (type == BluetoothSocket.TYPE_RFCOMM
@@ -267,6 +312,11 @@ public final class BluetoothSocket implements Closeable {
mPort = port;
// this constructor to be called only from BluetoothServerSocket
mDevice = null;
+ mDataPath = dataPath;
+ mSocketName = socketName;
+ mHubId = hubId;
+ mEndpointId = endpointId;
+ mMaximumPacketSize = maximumPacketSize;
mSocketState = SocketState.INIT;
@@ -322,6 +372,55 @@ public final class BluetoothSocket implements Closeable {
boolean pitm,
boolean min16DigitPin)
throws IOException {
+ this(
+ device,
+ type,
+ auth,
+ encrypt,
+ port,
+ uuid,
+ pitm,
+ min16DigitPin,
+ 0,
+ DEFAULT_SOCKET_NAME,
+ 0,
+ 0,
+ 0);
+ }
+
+ /**
+ * Construct a BluetoothSocket.
+ *
+ * @param device remote device that this socket can connect to
+ * @param type type of socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param port remote port
+ * @param uuid SDP uuid
+ * @param pitm enforce person-in-the-middle protection.
+ * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
+ * @param dataPath data path used for this socket
+ * @param socketName user-friendly name for this socket
+ * @param hubId ID of the hub to which the end point belongs
+ * @param endpointId ID of the endpoint within the hub that is associated with this socket
+ * @param maximumPacketSize The maximum size (in bytes) of a single data packet
+ * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
+ */
+ /*package*/ BluetoothSocket(
+ @NonNull BluetoothDevice device,
+ int type,
+ boolean auth,
+ boolean encrypt,
+ int port,
+ ParcelUuid uuid,
+ boolean pitm,
+ boolean min16DigitPin,
+ int dataPath,
+ @NonNull String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize)
+ throws IOException {
if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
mSocketCreationTimeNanos = System.nanoTime();
if (type == BluetoothSocket.TYPE_RFCOMM
@@ -343,6 +442,11 @@ public final class BluetoothSocket implements Closeable {
mEncrypt = encrypt;
mDevice = device;
mPort = port;
+ mDataPath = dataPath;
+ mSocketName = socketName;
+ mHubId = hubId;
+ mEndpointId = endpointId;
+ mMaximumPacketSize = maximumPacketSize;
mSocketState = SocketState.INIT;
@@ -393,11 +497,17 @@ public final class BluetoothSocket implements Closeable {
mMaxRxPacketSize = s.mMaxRxPacketSize;
mMaxTxPacketSize = s.mMaxTxPacketSize;
mConnectionUuid = s.mConnectionUuid;
+ mSocketId = s.mSocketId;
mServiceName = s.mServiceName;
mExcludeSdp = s.mExcludeSdp;
mAuthPitm = s.mAuthPitm;
mMin16DigitPin = s.mMin16DigitPin;
+ mDataPath = s.mDataPath;
+ mSocketName = s.mSocketName;
+ mHubId = s.mHubId;
+ mEndpointId = s.mEndpointId;
+ mMaximumPacketSize = s.mMaximumPacketSize;
mSocketCreationTimeNanos = s.mSocketCreationTimeNanos;
mSocketCreationLatencyNanos = s.mSocketCreationLatencyNanos;
}
@@ -524,11 +634,17 @@ public final class BluetoothSocket implements Closeable {
*
* <p>{@link #close} can be used to abort this call from another thread.
*
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
+ * {@code mDataPath} is different from {@link BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
+ *
* @throws BluetoothSocketException in case of failure, with the corresponding error code.
* @throws IOException for other errors (eg: InputStream read failures etc.).
*/
+ @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
@RequiresBluetoothConnectPermission
- @RequiresPermission(BLUETOOTH_CONNECT)
+ @RequiresPermission(
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
public void connect() throws IOException {
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
long socketConnectionTimeNanos = System.nanoTime();
@@ -547,7 +663,30 @@ public final class BluetoothSocket implements Closeable {
if (socketManager == null) {
throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE);
}
- mPfd = socketManager.connectSocket(mDevice, mType, mUuid, mPort, getSecurityFlags());
+ if (Flags.socketSettingsApi()) {
+ if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ mPfd =
+ socketManager.connectSocket(
+ mDevice, mType, mUuid, mPort, getSecurityFlags());
+ } else {
+ mPfd =
+ socketManager.connectSocketwithOffload(
+ mDevice,
+ mType,
+ mUuid,
+ mPort,
+ getSecurityFlags(),
+ mDataPath,
+ mSocketName,
+ mHubId,
+ mEndpointId,
+ mMaximumPacketSize);
+ }
+ } else {
+ mPfd =
+ socketManager.connectSocket(
+ mDevice, mType, mUuid, mPort, getSecurityFlags());
+ }
synchronized (this) {
Log.i(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
if (mSocketState == SocketState.CLOSED) {
@@ -675,7 +814,7 @@ public final class BluetoothSocket implements Closeable {
if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort);
if (mPort <= -1) {
mPort = channel;
- } // else ASSERT(mPort == channel)
+ }
ret = 0;
} catch (IOException e) {
if (mPfd != null) {
@@ -692,6 +831,98 @@ public final class BluetoothSocket implements Closeable {
return ret;
}
+ /**
+ * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can
+ * check the error code for EADDRINUSE
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
+ /*package*/ int bindListenWithOffload() {
+ int ret;
+ if (mSocketState == SocketState.CLOSED) return EBADFD;
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "bindListenWithOffload() fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if (DBG) Log.d(TAG, "bindListenWithOffload(): mPort=" + mPort + ", mType=" + mType);
+ IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
+ if (socketManager == null) {
+ Log.e(TAG, "bindListenWithOffload() bt get socket manager failed");
+ return -1;
+ }
+ mPfd =
+ socketManager.createSocketChannelWithOffload(
+ mType,
+ mServiceName,
+ mUuid,
+ mPort,
+ getSecurityFlags(),
+ mDataPath,
+ mSocketName,
+ mHubId,
+ mEndpointId,
+ mMaximumPacketSize);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+
+ // read out port number
+ try {
+ synchronized (this) {
+ if (DBG) {
+ Log.d(
+ TAG,
+ "bindListenWithOffload(), SocketState: "
+ + mSocketState
+ + ", mPfd: "
+ + mPfd);
+ }
+ if (mSocketState != SocketState.INIT) return EBADFD;
+ if (mPfd == null) return -1;
+ FileDescriptor fd = mPfd.getFileDescriptor();
+ if (fd == null) {
+ Log.e(TAG, "bindListenWithOffload(), null file descriptor");
+ return -1;
+ }
+
+ if (DBG) Log.d(TAG, "bindListenWithOffload(), Create LocalSocket");
+ mSocket = new LocalSocket(fd);
+ if (DBG) Log.d(TAG, "bindListenWithOffload(), new LocalSocket.getInputStream()");
+ mSocketIS = mSocket.getInputStream();
+ mSocketOS = mSocket.getOutputStream();
+ }
+ if (DBG) Log.d(TAG, "bindListenWithOffload(), readInt mSocketIS: " + mSocketIS);
+ int channel = readInt(mSocketIS);
+ synchronized (this) {
+ if (mSocketState == SocketState.INIT) {
+ mSocketState = SocketState.LISTENING;
+ }
+ }
+ if (DBG) Log.d(TAG, "bindListenWithOffload(): channel=" + channel + ", mPort=" + mPort);
+ if (mPort <= -1) {
+ mPort = channel;
+ }
+ ret = 0;
+ } catch (IOException e) {
+ if (mPfd != null) {
+ try {
+ mPfd.close();
+ } catch (IOException e1) {
+ Log.e(TAG, "bindListenWithOffload, close mPfd: " + e1);
+ }
+ mPfd = null;
+ }
+ Log.e(TAG, "bindListenWithOffload, fail to get port number, exception: " + e);
+ return -1;
+ }
+ return ret;
+ }
+
/*package*/ BluetoothSocket accept(int timeout) throws IOException {
BluetoothSocket acceptedSocket;
if (mSocketState != SocketState.LISTENING) {
@@ -701,7 +932,13 @@ public final class BluetoothSocket implements Closeable {
if (timeout > 0) {
mSocket.setSoTimeout(timeout);
}
- String RemoteAddr = waitSocketSignal(mSocketIS);
+ sendSocketAcceptSignal(mSocketOS, true);
+ String RemoteAddr;
+ try {
+ RemoteAddr = waitSocketSignal(mSocketIS);
+ } finally {
+ sendSocketAcceptSignal(mSocketOS, false);
+ }
if (timeout > 0) {
mSocket.setSoTimeout(0);
}
@@ -757,7 +994,7 @@ public final class BluetoothSocket implements Closeable {
ret = mSocketIS.read(b, offset, length);
}
if (ret < 0) {
- throw new IOException("bt socket closed, read return: " + ret);
+ return -1;
}
if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret);
return ret;
@@ -836,6 +1073,7 @@ public final class BluetoothSocket implements Closeable {
mPfd = null;
}
mConnectionUuid = null;
+ mSocketId = INVALID_SOCKET_ID;
}
}
}
@@ -1016,6 +1254,25 @@ public final class BluetoothSocket implements Closeable {
return cid;
}
+ /**
+ * Returns the socket ID assigned to the open connection on this BluetoothSocket. This socket ID
+ * is a unique identifier for the socket. It is valid only while the socket is connected.
+ *
+ * @return The socket ID in connected state.
+ * @throws BluetoothSocketException If the socket is not connected or an error occurs while
+ * retrieving the socket ID.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
+ @RequiresNoPermission
+ public long getSocketId() throws IOException {
+ if (mSocketState != SocketState.CONNECTED || mSocketId == INVALID_SOCKET_ID) {
+ throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
+ }
+ return mSocketId;
+ }
+
/** @hide */
@RequiresNoPermission
public ParcelFileDescriptor getParcelFileDescriptor() {
@@ -1034,17 +1291,53 @@ public final class BluetoothSocket implements Closeable {
addr[5]);
}
+ /**
+ * Sends a socket accept signal to the host stack.
+ *
+ * <p>This method is used to notify the host stack whether the host application is actively
+ * accepting a new connection or not. It sends a signal containing the acceptance status to the
+ * output stream associated with the socket.
+ *
+ * <p>This method is only effective when the data path is not {@link
+ * BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
+ *
+ * @param os The output stream to write the signal to.
+ * @param isAccepting {@code true} if the socket connection is being accepted, {@code false}
+ * otherwise.
+ * @throws IOException If an I/O error occurs while writing to the output stream.
+ * @hide
+ */
+ private void sendSocketAcceptSignal(OutputStream os, boolean isAccepting) throws IOException {
+ if (Flags.socketSettingsApi()) {
+ if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
+ return;
+ }
+ Log.d(TAG, "sendSocketAcceptSignal" + " isAccepting " + isAccepting);
+ byte[] sig = new byte[SOCK_ACCEPT_SIGNAL_SIZE];
+ ByteBuffer bb = ByteBuffer.wrap(sig);
+ bb.order(ByteOrder.nativeOrder());
+ bb.putShort((short) SOCK_ACCEPT_SIGNAL_SIZE);
+ bb.putShort((short) (isAccepting ? 1 : 0));
+ os.write(sig, 0, SOCK_ACCEPT_SIGNAL_SIZE);
+ }
+ }
+
private String waitSocketSignal(InputStream is) throws IOException {
- byte[] sig = new byte[SOCK_SIGNAL_SIZE];
+ byte[] sig = new byte[SOCK_CONNECTION_SIGNAL_SIZE];
int ret = readAll(is, sig);
if (VDBG) {
- Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret);
+ Log.d(
+ TAG,
+ "waitSocketSignal read "
+ + SOCK_CONNECTION_SIGNAL_SIZE
+ + " bytes signal ret: "
+ + ret);
}
ByteBuffer bb = ByteBuffer.wrap(sig);
/* the struct in native is decorated with __attribute__((packed)), hence this is possible */
bb.order(ByteOrder.nativeOrder());
int size = bb.getShort();
- if (size != SOCK_SIGNAL_SIZE) {
+ if (size != SOCK_CONNECTION_SIGNAL_SIZE) {
throw new IOException("Connection failure, wrong signal size: " + size);
}
byte[] addr = new byte[6];
@@ -1056,6 +1349,7 @@ public final class BluetoothSocket implements Closeable {
long uuidLsb = bb.getLong();
long uuidMsb = bb.getLong();
mConnectionUuid = new ParcelUuid(new UUID(uuidMsb, uuidLsb));
+ mSocketId = bb.getLong();
String RemoteAddr = convertAddr(addr);
if (VDBG) {
Log.d(
@@ -1073,7 +1367,9 @@ public final class BluetoothSocket implements Closeable {
+ " MaxTxPktSize: "
+ mMaxTxPacketSize
+ " mConnectionUuid: "
- + mConnectionUuid.toString());
+ + mConnectionUuid.toString()
+ + " mSocketId: "
+ + mSocketId);
}
if (status != 0) {
throw new IOException("Connection failure, status: " + status);
diff --git a/framework/java/android/bluetooth/BluetoothSocketException.java b/framework/java/android/bluetooth/BluetoothSocketException.java
index aba95a375a..4e163b7313 100644
--- a/framework/java/android/bluetooth/BluetoothSocketException.java
+++ b/framework/java/android/bluetooth/BluetoothSocketException.java
@@ -18,21 +18,18 @@ package android.bluetooth;
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
-import com.android.bluetooth.flags.Flags;
-
import java.io.IOException;
import java.lang.annotation.Retention;
/**
* Thrown when an error occurs during a Bluetooth Socket related exception.
*
- * <p>This is currently only intended to be thrown for a failure during {@link
- * BluetoothSocket#connect()} operation.
+ * <p>This is currently intended to be thrown for a failure during {@link BluetoothSocket}
+ * operations.
*/
public class BluetoothSocketException extends IOException {
@@ -70,8 +67,8 @@ public class BluetoothSocketException extends IOException {
public static final int UNSPECIFIED = 0;
/**
- * Error code during connect when socket connection fails for unknown reason during L2CAP
- * connection.
+ * Error code returned by {@link BluetoothSocket} during a L2CAP-related socket operation that
+ * failed for an unknown reason.
*/
public static final int L2CAP_UNKNOWN = 1;
@@ -141,13 +138,22 @@ public class BluetoothSocketException extends IOException {
/** Error code during connect when L2CAP connection timeout. */
public static final int L2CAP_TIMEOUT = 14;
- /** Error code during connect when Bluetooth is off and socket connection is triggered. */
+ /**
+ * Error code returned by {@link BluetoothSocket} during a socket operation that failed because
+ * Bluetooth is turned off.
+ */
public static final int BLUETOOTH_OFF_FAILURE = 15;
- /** Error code during connect when socket manager is not available. */
+ /**
+ * Error code returned by {@link BluetoothSocket} during a socket operation that failed because
+ * socket manager is not available.
+ */
public static final int SOCKET_MANAGER_FAILURE = 16;
- /** Error code during connect when socket is closed. */
+ /**
+ * Error code returned by {@link BluetoothSocket} during a socket operation that failed because
+ * the socket has been closed.
+ */
public static final int SOCKET_CLOSED = 17;
/** Error code during connect for generic socket connection failures. */
@@ -160,7 +166,6 @@ public class BluetoothSocketException extends IOException {
public static final int RPC_FAILURE = 20;
/** Error code during connect when the UNIX socket connection creation fails. */
- @FlaggedApi(Flags.FLAG_UNIX_FILE_SOCKET_CREATION_FAILURE)
public static final int UNIX_FILE_SOCKET_CREATION_FAILURE = 21;
/* Corresponding messages for respective error codes. */
diff --git a/framework/java/android/bluetooth/BluetoothSocketSettings.java b/framework/java/android/bluetooth/BluetoothSocketSettings.java
index 6fa8b0dc8b..b7706d50fe 100644
--- a/framework/java/android/bluetooth/BluetoothSocketSettings.java
+++ b/framework/java/android/bluetooth/BluetoothSocketSettings.java
@@ -18,14 +18,21 @@ package android.bluetooth;
import static android.bluetooth.BluetoothSocket.SocketType;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresNoPermission;
+import android.annotation.SystemApi;
import com.android.bluetooth.flags.Flags;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
@@ -42,6 +49,64 @@ public final class BluetoothSocketSettings {
private static final int L2CAP_PSM_UNSPECIFIED = -1;
+ /**
+ * Annotation to define the data path used for Bluetooth socket communication. This determines
+ * how data flows between the application and the Bluetooth controller.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = {"DATA_PATH_"},
+ value = {DATA_PATH_NO_OFFLOAD, DATA_PATH_HARDWARE_OFFLOAD})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SocketDataPath {}
+
+ /**
+ * Non-offload data path where the application's socket data is processed by the main Bluetooth
+ * stack.
+ *
+ * @hide
+ */
+ @SystemApi public static final int DATA_PATH_NO_OFFLOAD = 0;
+
+ /**
+ * Hardware offload data path where the application's socket data is processed by a offloaded
+ * application running on the low-power processor.
+ *
+ * <p>Using this data path requires the {@code BLUETOOTH_PRIVILEGED} permission, which will be
+ * checked when a socket connection or channel is created.
+ *
+ * @hide
+ */
+ @SystemApi public static final int DATA_PATH_HARDWARE_OFFLOAD = 1;
+
+ /**
+ * Maximum size (in bytes) of a data packet that can be received from the endpoint when using
+ * {@link #DATA_PATH_HARDWARE_OFFLOAD}.
+ */
+ @SystemApi private static final int HARDWARE_OFFLOAD_PACKET_MAX_SIZE = 65535;
+
+ /**
+ * Maximum length (in bytes) of a socket name when using {@link #DATA_PATH_HARDWARE_OFFLOAD}.
+ */
+ @SystemApi private static final int HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH = 127;
+
+ /**
+ * Constant representing an invalid hub ID. This value indicates that a hub ID has not been
+ * assigned or is not valid.
+ *
+ * @hide
+ */
+ private static final long INVALID_HUB_ID = 0;
+
+ /**
+ * Constant representing an invalid hub endpoint ID. This value indicates that an endpoint ID
+ * has not been assigned or is not valid.
+ *
+ * @hide
+ */
+ private static final long INVALID_ENDPOINT_ID = 0;
+
/** Type of the Bluetooth socket */
@SocketType private int mSocketType;
@@ -61,6 +126,50 @@ public final class BluetoothSocketSettings {
private UUID mRfcommUuid;
/**
+ * Specifies the data path used for this socket, influencing how data is transmitted and
+ * processed. Select the appropriate data path based on performance and power consumption
+ * requirements:
+ *
+ * <ul>
+ * <li>{@link #DATA_PATH_NO_OFFLOAD}: Suitable for applications that require the full
+ * processing capabilities of the main Bluetooth stack.
+ * <li>{@link #DATA_PATH_HARDWARE_OFFLOAD}: Optimized for lower power consumption by utilizing
+ * an offloaded application running on a dedicated low-power processor.
+ * </ul>
+ */
+ @SocketDataPath private int mDataPath;
+
+ /**
+ * A user-friendly name for this socket, primarily for debugging and logging. This name should
+ * be descriptive and can help identify the socket during development and troubleshooting.
+ *
+ * <p>When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this name is also passed to the offloaded
+ * application running on the low-power processor. This allows the offloaded application to
+ * identify and manage the socket.
+ */
+ private String mSocketName;
+
+ /**
+ * When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this identifies the hub hosting the endpoint.
+ *
+ * <p>Hub represents a logical/physical representation of multiple endpoints. A pair of {@code
+ * mHubId} and {@code mEndpointId} uniquely identifies the endpoint globally.
+ */
+ private long mHubId;
+
+ /**
+ * When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this identifies the specific endpoint within
+ * the hub that is associated with this socket.
+ */
+ private long mEndpointId;
+
+ /**
+ * The maximum size (in bytes) of a single data packet that can be received from the endpoint
+ * when using {@link #DATA_PATH_HARDWARE_OFFLOAD}.
+ */
+ private int mMaximumPacketSize;
+
+ /**
* Returns the type of the Bluetooth socket.
*
* <p>Defaults to {@code BluetoothSocket#TYPE_RFCOMM}.
@@ -120,35 +229,137 @@ public final class BluetoothSocketSettings {
}
/**
+ * Returns the data path used for this socket. The data path determines how data is routed and
+ * processed for the socket connection.
+ *
+ * <p>Defaults to {@link #DATA_PATH_NO_OFFLOAD}.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresNoPermission
+ public @SocketDataPath int getDataPath() {
+ return mDataPath;
+ }
+
+ /**
+ * Returns the user-friendly name assigned to this socket. This name is primarily used for
+ * debugging and logging purposes.
+ *
+ * <p>When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this name is also passed to the offloaded
+ * application running on the low-power processor.
+ *
+ * <p>Defaults to {@code null} if no name was explicitly set.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresNoPermission
+ public String getSocketName() {
+ return mSocketName;
+ }
+
+ /**
+ * Returns the ID of the hub associated with this socket when using {@link
+ * #DATA_PATH_HARDWARE_OFFLOAD}.
+ *
+ * <p>If the data path is not set to {@link #DATA_PATH_HARDWARE_OFFLOAD}, this method returns
+ * {@link #INVALID_HUB_ID}.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresNoPermission
+ public long getHubId() {
+ if (mDataPath != DATA_PATH_HARDWARE_OFFLOAD) {
+ return INVALID_HUB_ID;
+ }
+ return mHubId;
+ }
+
+ /**
+ * Returns the ID of the endpoint within the hub associated with this socket when using {@link
+ * #DATA_PATH_HARDWARE_OFFLOAD}. An endpoint represents a specific point of communication within
+ * the hub.
+ *
+ * <p>If the data path is not set to {@link #DATA_PATH_HARDWARE_OFFLOAD}, this method returns
+ * {@link #INVALID_ENDPOINT_ID}.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresNoPermission
+ public long getEndpointId() {
+ if (mDataPath != DATA_PATH_HARDWARE_OFFLOAD) {
+ return INVALID_ENDPOINT_ID;
+ }
+ return mEndpointId;
+ }
+
+ /**
+ * Returns the requested maximum size (in bytes) of a data packet that can be received from the
+ * endpoint associated with this socket when using {@link #DATA_PATH_HARDWARE_OFFLOAD}.
+ *
+ * <p>Defaults to {@link #HARDWARE_OFFLOAD_PACKET_MAX_SIZE}.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresNoPermission
+ public int getRequestedMaximumPacketSize() {
+ return mMaximumPacketSize;
+ }
+
+ /**
* Returns a {@link String} that describes each BluetoothSocketSettings parameter current value.
*/
@Override
public String toString() {
+ StringBuilder builder = new StringBuilder("BluetoothSocketSettings{");
+ builder.append("mSocketType=")
+ .append(mSocketType)
+ .append(", mEncryptionRequired=")
+ .append(mEncryptionRequired)
+ .append(", mAuthenticationRequired=")
+ .append(mAuthenticationRequired);
if (mSocketType == BluetoothSocket.TYPE_RFCOMM) {
- return "BluetoothSocketSettings{"
- + "mSocketType="
- + mSocketType
- + ", mEncryptionRequired="
- + mEncryptionRequired
- + ", mAuthenticationRequired="
- + mAuthenticationRequired
- + ", mRfcommServiceName="
- + mRfcommServiceName
- + ", mRfcommUuid="
- + mRfcommUuid
- + "}";
+ builder.append(", mRfcommServiceName=")
+ .append(mRfcommServiceName)
+ .append(", mRfcommUuid=")
+ .append(mRfcommUuid);
} else {
- return "BluetoothSocketSettings{"
- + "mSocketType="
- + mSocketType
- + ", mL2capPsm="
- + mL2capPsm
- + ", mEncryptionRequired="
- + mEncryptionRequired
- + ", mAuthenticationRequired="
- + mAuthenticationRequired
- + "}";
+ builder.append(", mL2capPsm=").append(mL2capPsm);
+ }
+ if (mDataPath == DATA_PATH_HARDWARE_OFFLOAD) {
+ builder.append(", mDataPath=")
+ .append(mDataPath)
+ .append(", mSocketName=")
+ .append(mSocketName)
+ .append(", mHubId=")
+ .append(mHubId)
+ .append(", mEndpointId=")
+ .append(mEndpointId)
+ .append(", mMaximumPacketSize=")
+ .append(mMaximumPacketSize);
}
+ builder.append("}");
+ return builder.toString();
}
private BluetoothSocketSettings(
@@ -157,13 +368,23 @@ public final class BluetoothSocketSettings {
boolean encryptionRequired,
boolean authenticationRequired,
String rfcommServiceName,
- UUID rfcommUuid) {
+ UUID rfcommUuid,
+ int dataPath,
+ String socketName,
+ long hubId,
+ long endpointId,
+ int maximumPacketSize) {
mSocketType = socketType;
mL2capPsm = l2capPsm;
mEncryptionRequired = encryptionRequired;
mAuthenticationRequired = authenticationRequired;
mRfcommUuid = rfcommUuid;
mRfcommServiceName = rfcommServiceName;
+ mDataPath = dataPath;
+ mSocketName = socketName;
+ mHubId = hubId;
+ mEndpointId = endpointId;
+ mMaximumPacketSize = maximumPacketSize;
}
/** Builder for {@link BluetoothSocketSettings}. */
@@ -175,6 +396,11 @@ public final class BluetoothSocketSettings {
private boolean mAuthenticationRequired = false;
private String mRfcommServiceName = null;
private UUID mRfcommUuid = null;
+ private int mDataPath = DATA_PATH_NO_OFFLOAD;
+ private String mSocketName = BluetoothSocket.DEFAULT_SOCKET_NAME;
+ private long mHubId = INVALID_HUB_ID;
+ private long mEndpointId = INVALID_ENDPOINT_ID;
+ private int mMaximumPacketSize = HARDWARE_OFFLOAD_PACKET_MAX_SIZE;
public Builder() {}
@@ -303,6 +529,126 @@ public final class BluetoothSocketSettings {
}
/**
+ * Sets the data path for this socket. The data path determines how data is routed and
+ * processed for the socket connection.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @param dataPath The desired data path for the socket.
+ * @return This Builder object to allow for method chaining.
+ * @throws IllegalArgumentException If {@code dataPath} is an invalid value.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresNoPermission
+ public Builder setDataPath(@SocketDataPath int dataPath) {
+ if (dataPath < DATA_PATH_NO_OFFLOAD || dataPath > DATA_PATH_HARDWARE_OFFLOAD) {
+ throw new IllegalArgumentException("Invalid dataPath - " + dataPath);
+ }
+ mDataPath = dataPath;
+ return this;
+ }
+
+ /**
+ * Sets a user-friendly name for this socket. This name is primarily used for debugging and
+ * logging purposes.
+ *
+ * <p>When using {@link #DATA_PATH_HARDWARE_OFFLOAD}, this name is also passed to the
+ * offloaded application running on low-power processor.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @param socketName The desired name for the socket. This should be a descriptive name that
+ * helps identify the socket during development and troubleshooting. The socket name
+ * cannot exceed {@link #HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH} bytes in length when
+ * encoded in UTF-8.
+ * @return This Builder object to allow for method chaining.
+ * @throws IllegalArgumentException if the provided `socketName` exceeds {@link
+ * #HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH} bytes when encoded in UTF-8.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresNoPermission
+ public Builder setSocketName(@NonNull String socketName) {
+ byte[] socketNameBytes = requireNonNull(socketName).getBytes(StandardCharsets.UTF_8);
+ if (socketNameBytes.length > HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH) {
+ throw new IllegalArgumentException(
+ "Socket name cannot exceed "
+ + HARDWARE_OFFLOAD_SOCKET_NAME_MAX_LENGTH
+ + " bytes in length when encoded in UTF-8.");
+ }
+ mSocketName = requireNonNull(socketName);
+ return this;
+ }
+
+ /**
+ * Sets the ID of the hub to be associated with this socket when using {@link
+ * #DATA_PATH_HARDWARE_OFFLOAD}.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @param hubId The ID of the hub.
+ * @return This Builder object to allow for method chaining.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresNoPermission
+ public Builder setHubId(long hubId) {
+ mHubId = hubId;
+ return this;
+ }
+
+ /**
+ * Sets the ID of the endpoint within the hub to be associated with this socket when using
+ * {@link #DATA_PATH_HARDWARE_OFFLOAD}. An endpoint represents a specific point of
+ * communication within the hub.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @param endpointId The ID of the endpoint within the hub.
+ * @return This Builder object to allow for method chaining.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresNoPermission
+ public Builder setEndpointId(long endpointId) {
+ mEndpointId = endpointId;
+ return this;
+ }
+
+ /**
+ * Sets the requested maximum size (in bytes) of a data packet that can be received from the
+ * endpoint associated with this socket when using {@link #DATA_PATH_HARDWARE_OFFLOAD}.
+ *
+ * <p>The main Bluetooth stack may adjust this value based on the actual capabilities
+ * negotiated with the peer device during connection establishment. To get the final
+ * negotiated value, use {@link BluetoothSocket#getMaxReceivePacketSize()} after the socket
+ * is connected.
+ *
+ * <p>This API is part of the System API because {@link #DATA_PATH_HARDWARE_OFFLOAD} is only
+ * available through the System API.
+ *
+ * @param maximumPacketSize The maximum packet size in bytes.
+ * @return This Builder object to allow for method chaining.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresNoPermission
+ public Builder setRequestedMaximumPacketSize(int maximumPacketSize) {
+ mMaximumPacketSize = maximumPacketSize;
+ return this;
+ }
+
+ /**
* Builds a {@link BluetoothSocketSettings} object.
*
* @return A new {@link BluetoothSocketSettings} object with the configured parameters.
@@ -336,14 +682,32 @@ public final class BluetoothSocketSettings {
+ mRfcommUuid);
}
}
-
+ if (mDataPath == DATA_PATH_HARDWARE_OFFLOAD) {
+ if (mHubId == INVALID_HUB_ID || mEndpointId == INVALID_ENDPOINT_ID) {
+ throw new IllegalArgumentException(
+ "Hub ID and endpoint ID must be set for hardware data path");
+ }
+ if (mMaximumPacketSize < 0) {
+ throw new IllegalArgumentException("invalid packet size " + mMaximumPacketSize);
+ }
+ } else {
+ if (mHubId != INVALID_HUB_ID || mEndpointId != INVALID_ENDPOINT_ID) {
+ throw new IllegalArgumentException(
+ "Hub ID and endpoint ID may not be set for software data path");
+ }
+ }
return new BluetoothSocketSettings(
mSocketType,
mL2capPsm,
mEncryptionRequired,
mAuthenticationRequired,
mRfcommServiceName,
- mRfcommUuid);
+ mRfcommUuid,
+ mDataPath,
+ mSocketName,
+ mHubId,
+ mEndpointId,
+ mMaximumPacketSize);
}
}
}
diff --git a/framework/java/android/bluetooth/le/AdvertisingSet.java b/framework/java/android/bluetooth/le/AdvertisingSet.java
index 2a5b2dc323..8632fcf671 100644
--- a/framework/java/android/bluetooth/le/AdvertisingSet.java
+++ b/framework/java/android/bluetooth/le/AdvertisingSet.java
@@ -136,11 +136,17 @@ public final class AdvertisingSet {
* advertising is not active. This method returns immediately, the operation status is delivered
* through {@code callback.onAdvertisingParametersUpdated}.
*
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission when
+ * {@code parameters.getOwnAddressType()} is different from {@code
+ * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or {@code parameters.isDirected()} is true.
+ *
* @param parameters advertising set parameters.
*/
@RequiresLegacyBluetoothAdminPermission
@RequiresBluetoothAdvertisePermission
- @RequiresPermission(BLUETOOTH_ADVERTISE)
+ @RequiresPermission(
+ allOf = {BLUETOOTH_ADVERTISE, BLUETOOTH_PRIVILEGED},
+ conditional = true)
public void setAdvertisingParameters(AdvertisingSetParameters parameters) {
try {
mGatt.setAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource);
diff --git a/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 7b29261fe0..057053e817 100644
--- a/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/framework/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -269,9 +269,9 @@ public final class BluetoothLeAdvertiser {
* method returns immediately, the operation status is delivered through {@code
* callback.onAdvertisingSetStarted()}.
*
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission when
* {@code parameters.getOwnAddressType()} is different from {@code
- * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT}.
+ * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or {@code parameters.isDirected()} is true.
*
* <p>The {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission is always enforced.
*
@@ -319,9 +319,9 @@ public final class BluetoothLeAdvertiser {
* method returns immediately, the operation status is delivered through {@code
* callback.onAdvertisingSetStarted()}.
*
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission when
* {@code parameters.getOwnAddressType()} is different from {@code
- * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT}.
+ * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or {@code parameters.isDirected()} is true.
*
* <p>The {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission is always enforced.
*
@@ -371,9 +371,9 @@ public final class BluetoothLeAdvertiser {
* method returns immediately, the operation status is delivered through {@code
* callback.onAdvertisingSetStarted()}.
*
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission when
* {@code parameters.getOwnAddressType()} is different from {@code
- * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT}.
+ * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or {@code parameters.isDirected()} is true.
*
* <p>The {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission is always enforced.
*
@@ -428,9 +428,9 @@ public final class BluetoothLeAdvertiser {
* method returns immediately, the operation status is delivered through {@code
* callback.onAdvertisingSetStarted()}.
*
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission when
* {@code parameters.getOwnAddressType()} is different from {@code
- * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT}.
+ * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or {@code parameters.isDirected()} is true.
*
* <p>The {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission is always enforced.
*
@@ -494,10 +494,10 @@ public final class BluetoothLeAdvertiser {
* services/characteristics in this server, rather than the union of all GATT services (across
* all opened servers).
*
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
+ * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission when
* {@code parameters.getOwnAddressType()} is different from {@code
- * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or when the {@code gattServer} is already
- * registered
+ * AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT} or {@code parameters.isDirected()} is true or
+ * when the {@code gattServer} is already registered
*
* <p>The {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission is always enforced.
*
diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java
index c5f07d2092..1760bc0bf1 100644
--- a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java
+++ b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java
@@ -166,7 +166,8 @@ public final class DistanceMeasurementManager {
* Get the maximum supported security level of channel sounding between the local device and a
* specific remote device.
*
- * <p>See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+ * <p>See: Vol 3 Part C, Chapter 10.11.1 of
+ * https://bluetooth.com/specifications/specs/core60-html/
*
* @param remoteDevice remote device of channel sounding
* @return max supported security level, {@link ChannelSoundingParams#CS_SECURITY_LEVEL_UNKNOWN}
@@ -200,7 +201,8 @@ public final class DistanceMeasurementManager {
/**
* Get the maximum supported security level of channel sounding of the local device.
*
- * <p>See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+ * <p>See: Vol 3 Part C, Chapter 10.11.1 of
+ * https://bluetooth.com/specifications/specs/core60-html/
*
* @return max supported security level, {@link ChannelSoundingParams#CS_SECURITY_LEVEL_UNKNOWN}
* when Channel Sounding is not supported or encounters an internal error.
@@ -230,10 +232,13 @@ public final class DistanceMeasurementManager {
/**
* Get the set of supported security levels of channel sounding.
*
- * <p>See: https://bluetooth.com/specifications/specs/core60-html/
+ * <p>See: Vol 3 Part C, Chapter 10.11.1 of
+ * https://bluetooth.com/specifications/specs/core60-html/
*
- * @return the set of supported security levels, empty when Channel Sounding is not supported or
- * encounters an internal error.
+ * @return the set of supported security levels, empty when encounters an internal error.
+ * @throws UnsupportedOperationException if the {@link
+ * android.content.pm.PackageManager#FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING} is not
+ * supported.
* @hide
*/
@FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementResult.java b/framework/java/android/bluetooth/le/DistanceMeasurementResult.java
index e69e895fba..2292371e56 100644
--- a/framework/java/android/bluetooth/le/DistanceMeasurementResult.java
+++ b/framework/java/android/bluetooth/le/DistanceMeasurementResult.java
@@ -16,7 +16,6 @@
package android.bluetooth.le;
-import android.annotation.ElapsedRealtimeLong;
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -133,7 +132,7 @@ public final class DistanceMeasurementResult implements Parcelable {
private final double mConfidenceLevel;
private final int mDetectedAttackLevel;
private final double mVelocityMetersPerSecond;
- private final @ElapsedRealtimeLong long mMeasurementTimestampNanos;
+ private final long mMeasurementTimestampNanos;
private DistanceMeasurementResult(
double meters,
@@ -146,7 +145,7 @@ public final class DistanceMeasurementResult implements Parcelable {
double confidenceLevel,
@Nadm int detectedAttackLevel,
double velocityMetersPerSecond,
- @ElapsedRealtimeLong long measurementTimestampNanos) {
+ long measurementTimestampNanos) {
mMeters = meters;
mErrorMeters = errorMeters;
mAzimuthAngle = azimuthAngle;
@@ -313,7 +312,7 @@ public final class DistanceMeasurementResult implements Parcelable {
*/
@FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
@SystemApi
- public @ElapsedRealtimeLong long getMeasurementTimestampNanos() {
+ public long getMeasurementTimestampNanos() {
return mMeasurementTimestampNanos;
}
@@ -419,7 +418,7 @@ public final class DistanceMeasurementResult implements Parcelable {
private double mConfidenceLevel = Double.NaN;
private int mDetectedAttackLevel = NADM_UNKNOWN;
private double mVelocityMetersPerSecond = Double.NaN;
- private @ElapsedRealtimeLong long mMeasurementTimestampNanos = -1L;
+ private long mMeasurementTimestampNanos = -1L;
/**
* Constructor of the Builder.
@@ -602,8 +601,7 @@ public final class DistanceMeasurementResult implements Parcelable {
@FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
@SystemApi
@NonNull
- public Builder setMeasurementTimestampNanos(
- @ElapsedRealtimeLong long measurementTimestampNanos) {
+ public Builder setMeasurementTimestampNanos(long measurementTimestampNanos) {
mMeasurementTimestampNanos = measurementTimestampNanos;
return this;
}
diff --git a/framework/tests/bumble/Android.bp b/framework/tests/bumble/Android.bp
index 6c516acf11..968a458bad 100644
--- a/framework/tests/bumble/Android.bp
+++ b/framework/tests/bumble/Android.bp
@@ -18,6 +18,8 @@ android_test_helper_app {
"libprotobuf-java-micro",
],
+ jarjar_rules: ":bluetooth-jarjar-rules",
+
static_libs: [
"TestParameterInjector",
"androidx.core_core",
diff --git a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java
index 38671a28e9..c9fa50bbd9 100644
--- a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java
@@ -21,6 +21,8 @@ import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static com.google.common.truth.Truth.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -33,6 +35,7 @@ import static org.mockito.Mockito.verify;
import android.bluetooth.test_utils.EnableBluetoothRule;
import android.content.Context;
+import android.os.SystemProperties;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -93,6 +96,11 @@ public class GattClientTest {
private static final UUID TEST_CHARACTERISTIC_UUID =
UUID.fromString("00010001-0000-0000-0000-000000000000");
+ private static final int MIN_CONN_INTERVAL_RELAXED =
+ SystemProperties.getInt("bluetooth.core.le.min_connection_interval_relaxed", 0x0018);
+ private static final int MAX_CONN_INTERVAL_RELAXED =
+ SystemProperties.getInt("bluetooth.core.le.max_connection_interval_relaxed", 0x0028);
+
@Rule(order = 0)
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -172,6 +180,36 @@ public class GattClientTest {
disconnectAndWaitDisconnection(gatt, gattCallback);
}
+ @RequiresFlagsEnabled(Flags.FLAG_INITIAL_CONN_PARAMS_P1)
+ @Test
+ public void onConnectionUpdatedIsCalledOnlyOnceForRelaxingConnectionParameters_noGattCache() {
+ int aggressiveConnectionThreshold =
+ SystemProperties.getInt("bluetooth.core.le.aggressive_connection_threshold", 2);
+ // This test is for the case where aggressive initial parameters are used.
+ assumeThat(aggressiveConnectionThreshold, greaterThan(0));
+
+ BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class);
+ ArgumentCaptor<Integer> connectionIntervalCaptor = ArgumentCaptor.forClass(Integer.class);
+
+ BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback, false);
+
+ // Wait until service discovery is done and parameters are relaxed.
+ verify(gattCallback, timeout(10_000).times(1))
+ .onConnectionUpdated(
+ any(), connectionIntervalCaptor.capture(), anyInt(), anyInt(), anyInt());
+
+ List<Integer> capturedConnectionIntervals = connectionIntervalCaptor.getAllValues();
+ assertThat(capturedConnectionIntervals).hasSize(1);
+
+ // Since aggressive parameters are used in the initial connection,
+ // there should be only one connection parameters update event for relaxing them.
+ int relaxedConnIntervalAfterServiceDiscovery = capturedConnectionIntervals.get(0);
+ assertThat(relaxedConnIntervalAfterServiceDiscovery).isAtLeast(MIN_CONN_INTERVAL_RELAXED);
+ assertThat(relaxedConnIntervalAfterServiceDiscovery).isAtMost(MAX_CONN_INTERVAL_RELAXED);
+
+ disconnectAndWaitDisconnection(gatt, gattCallback);
+ }
+
@Test
public void reconnectExistingClient() throws Exception {
advertiseWithBumble();
diff --git a/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java
index 62e3f4f81e..1e718a7874 100644
--- a/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java
@@ -31,15 +31,11 @@ import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.flags.Flags;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import org.junit.Ignore;
@@ -62,14 +58,11 @@ public class GattServerConnectWithScanTest {
private static final int TIMEOUT_SCANNING_MS = 2_000;
private static final int TIMEOUT_GATT_CONNECTION_MS = 2_000;
- @Rule(order = 2)
- public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
-
@Rule(order = 1)
- public final PandoraDevice mBumble = new PandoraDevice();
+ public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
@Rule(order = 0)
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final PandoraDevice mBumble = new PandoraDevice();
private final Context mContext = ApplicationProvider.getApplicationContext();
private final BluetoothManager mBluetoothManager =
@@ -132,7 +125,6 @@ public class GattServerConnectWithScanTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION)
@Ignore("b/343749428: Remove hidden api's dependencies to enable the test.")
public void serverConnectToPublicAddress_withTransportAuto() throws Exception {
String publicAddress = mBumble.getRemoteDevice().getAddress();
diff --git a/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java
index ff676a069d..05af3c0b0e 100644
--- a/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java
@@ -26,14 +26,10 @@ import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.flags.Flags;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import org.junit.Ignore;
@@ -50,14 +46,11 @@ public class GattServerConnectWithoutScanTest {
private static final String TAG = "GattServerConnectWithoutScanTest";
private static final int TIMEOUT_GATT_CONNECTION_MS = 2_000;
- @Rule(order = 2)
- public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
-
@Rule(order = 1)
- public final PandoraDevice mBumble = new PandoraDevice();
+ public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
@Rule(order = 0)
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final PandoraDevice mBumble = new PandoraDevice();
private final Context mContext = ApplicationProvider.getApplicationContext();
private final BluetoothManager mBluetoothManager =
@@ -65,7 +58,6 @@ public class GattServerConnectWithoutScanTest {
private final BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
@Test
- @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION)
@Ignore("b/343749428: Remove hidden api's dependencies to enable the test.")
public void serverConnectToRandomAddress_withTransportAuto() throws Exception {
advertiseWithBumble(OwnAddressType.RANDOM);
@@ -92,7 +84,6 @@ public class GattServerConnectWithoutScanTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION)
@Ignore("b/343749428: Remove hidden api's dependencies to enable the test.")
public void serverConnectToRandomAddress_withTransportLE() throws Exception {
advertiseWithBumble(OwnAddressType.RANDOM);
diff --git a/framework/tests/bumble/src/android/bluetooth/LeLegacyAdvertisingTest.java b/framework/tests/bumble/src/android/bluetooth/LeLegacyAdvertisingTest.java
index 4927871280..39abb62c9c 100644
--- a/framework/tests/bumble/src/android/bluetooth/LeLegacyAdvertisingTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/LeLegacyAdvertisingTest.java
@@ -24,13 +24,9 @@ import android.bluetooth.le.AdvertisingSetCallback;
import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.os.ParcelUuid;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.bluetooth.flags.Flags;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import org.junit.Rule;
@@ -48,10 +44,6 @@ public class LeLegacyAdvertisingTest {
@Rule(order = 1)
public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
- @Rule(order = 0)
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- @RequiresFlagsEnabled(Flags.FLAG_BLE_CHECK_DATA_LENGTH_ON_LEGACY_ADVERTISING)
@Test
public void setAdvertisingDataOver31Bytes() throws Exception {
final BluetoothLeAdvertiser advertiser =
@@ -103,7 +95,6 @@ public class LeLegacyAdvertisingTest {
}
}
- @RequiresFlagsEnabled(Flags.FLAG_BLE_CHECK_DATA_LENGTH_ON_LEGACY_ADVERTISING)
@Test
public void setScanResponseDataOver31Bytes() throws Exception {
final BluetoothLeAdvertiser advertiser =
diff --git a/framework/tests/bumble/src/android/bluetooth/RfcommTest.kt b/framework/tests/bumble/src/android/bluetooth/RfcommTest.kt
index 64c29070ac..a952f54950 100644
--- a/framework/tests/bumble/src/android/bluetooth/RfcommTest.kt
+++ b/framework/tests/bumble/src/android/bluetooth/RfcommTest.kt
@@ -122,18 +122,6 @@ class RfcommTest {
mRemoteDevice = mBumble.remoteDevice
mHost = Host(mContext)
- // Set Bonding
- val pairingConfig =
- BumbleConfigProto.PairingConfig.newBuilder()
- .setBonding(false)
- .setMitm(false)
- .setSc(false)
- .setIdentityAddressType(HostProto.OwnAddressType.PUBLIC)
- .build()
- val overrideRequest =
- BumbleConfigProto.OverrideRequest.newBuilder().setPairingConfig(pairingConfig).build()
- mBumble.bumbleConfigBlocking().override(overrideRequest)
-
val bluetoothA2dp = getProfileProxy(mContext, BluetoothProfile.A2DP) as BluetoothA2dp
bluetoothA2dp.setConnectionPolicy(
mRemoteDevice,
@@ -176,6 +164,7 @@ class RfcommTest {
*/
@Test
fun clientConnectToOpenServerSocketInsecure() {
+ updateSecurityConfig()
startServer { serverId -> createConnectAcceptSocket(isSecure = false, serverId) }
}
@@ -187,6 +176,7 @@ class RfcommTest {
*/
@Test
fun clientConnectToOpenServerSocketSecure() {
+ updateSecurityConfig()
startServer { serverId -> createConnectAcceptSocket(isSecure = true, serverId) }
}
@@ -200,6 +190,7 @@ class RfcommTest {
*/
@Test
fun clientSendDataOverInsecureSocket() {
+ updateSecurityConfig()
startServer { serverId ->
val (insecureSocket, connection) = createConnectAcceptSocket(isSecure = false, serverId)
val data: ByteArray = "Test data for clientSendDataOverInsecureSocket".toByteArray()
@@ -225,6 +216,7 @@ class RfcommTest {
*/
@Test
fun clientSendDataOverSecureSocket() {
+ updateSecurityConfig()
startServer { serverId ->
val (secureSocket, connection) = createConnectAcceptSocket(isSecure = true, serverId)
val data: ByteArray = "Test data for clientSendDataOverSecureSocket".toByteArray()
@@ -250,6 +242,7 @@ class RfcommTest {
*/
@Test
fun clientReceiveDataOverInsecureSocket() {
+ updateSecurityConfig()
startServer { serverId ->
val (insecureSocket, connection) = createConnectAcceptSocket(isSecure = false, serverId)
val buffer = ByteArray(64)
@@ -276,6 +269,7 @@ class RfcommTest {
*/
@Test
fun clientReceiveDataOverSecureSocket() {
+ updateSecurityConfig()
startServer { serverId ->
val (secureSocket, connection) = createConnectAcceptSocket(isSecure = true, serverId)
val buffer = ByteArray(64)
@@ -303,6 +297,7 @@ class RfcommTest {
*/
@Test
fun connectTwoInsecureClientsSimultaneously() {
+ updateSecurityConfig()
startServer("ServerPort1", TEST_UUID) { serverId1 ->
startServer("ServerPort2", SERIAL_PORT_UUID) { serverId2 ->
val socket1 = createSocket(mRemoteDevice, isSecure = false, TEST_UUID)
@@ -326,6 +321,7 @@ class RfcommTest {
*/
@Test
fun connectTwoInsecureClientsSequentially() {
+ updateSecurityConfig()
startServer("ServerPort1", TEST_UUID) { serverId1 ->
startServer("ServerPort2", SERIAL_PORT_UUID) { serverId2 ->
val socket1 = createSocket(mRemoteDevice, isSecure = false, TEST_UUID)
@@ -350,6 +346,7 @@ class RfcommTest {
*/
@Test
fun connectTwoSecureClientsSimultaneously() {
+ updateSecurityConfig()
startServer("ServerPort1", TEST_UUID) { serverId1 ->
startServer("ServerPort2", SERIAL_PORT_UUID) { serverId2 ->
val socket2 = createSocket(mRemoteDevice, isSecure = true, SERIAL_PORT_UUID)
@@ -373,6 +370,7 @@ class RfcommTest {
*/
@Test
fun connectTwoSecureClientsSequentially() {
+ updateSecurityConfig()
startServer("ServerPort1", TEST_UUID) { serverId1 ->
startServer("ServerPort2", SERIAL_PORT_UUID) { serverId2 ->
val socket1 = createSocket(mRemoteDevice, isSecure = true, TEST_UUID)
@@ -396,6 +394,7 @@ class RfcommTest {
@Test
@Ignore("b/380091558")
fun connectTwoMixedClientsInsecureThenSecure() {
+ updateSecurityConfig()
startServer("ServerPort1", TEST_UUID) { serverId1 ->
startServer("ServerPort2", SERIAL_PORT_UUID) { serverId2 ->
val socket2 = createSocket(mRemoteDevice, isSecure = false, SERIAL_PORT_UUID)
@@ -418,6 +417,7 @@ class RfcommTest {
*/
@Test
fun connectTwoMixedClientsSecureThenInsecure() {
+ updateSecurityConfig()
startServer("ServerPort1", TEST_UUID) { serverId1 ->
startServer("ServerPort2", SERIAL_PORT_UUID) { serverId2 ->
val socket2 = createSocket(mRemoteDevice, isSecure = true, SERIAL_PORT_UUID)
@@ -439,6 +439,7 @@ class RfcommTest {
@RequiresFlagsEnabled(Flags.FLAG_TRIGGER_SEC_PROC_ON_INC_ACCESS_REQ)
@Test
fun serverSecureConnectThenRemoteDisconnect() {
+ updateSecurityConfig()
// step 1
val (serverSock, connection) = connectRemoteToListeningSocket()
val disconnectRequest =
@@ -456,6 +457,7 @@ class RfcommTest {
@RequiresFlagsEnabled(Flags.FLAG_TRIGGER_SEC_PROC_ON_INC_ACCESS_REQ)
@Test
fun serverSecureConnectThenLocalDisconnect() {
+ updateSecurityConfig()
// step 1
val (serverSock, _) = connectRemoteToListeningSocket()
// step 2
@@ -463,6 +465,127 @@ class RfcommTest {
Truth.assertThat(serverSock.channel).isEqualTo(-1) // ensure disconnected at RFCOMM Layer
}
+ /*
+ Test Steps:
+ 1. Create an insecure socket
+ 2. Connect to the socket
+ 3. Verify that devices are connected
+ 4. Write data to socket output stream
+ 5. Verify bumble received that data
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_SOCKET_SETTINGS_API)
+ fun clientSendDataOverInsecureSocketUsingSocketSettings() {
+ updateSecurityConfig()
+ startServer { serverId ->
+ val (insecureSocket, connection) = createConnectAcceptSocketUsingSettings(serverId)
+ val data: ByteArray =
+ "Test data for clientSendDataOverInsecureSocketUsingSocketSettings".toByteArray()
+ val socketOs = insecureSocket.outputStream
+
+ socketOs.write(data)
+ val rxResponse: RfcommProto.RxResponse =
+ mBumble
+ .rfcommBlocking()
+ .withDeadlineAfter(GRPC_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
+ .receive(RfcommProto.RxRequest.newBuilder().setConnection(connection).build())
+ Truth.assertThat(rxResponse.data).isEqualTo(ByteString.copyFrom(data))
+ }
+ }
+
+ /*
+ Test Steps:
+ 1. Create an encrypt only socket
+ 2. Connect to the socket
+ 3. Verify that devices are connected
+ 4. Write data to socket output stream
+ 5. Verify bumble received that data
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_SOCKET_SETTINGS_API)
+ fun clientSendDataOverEncryptedOnlySocketUsingSocketSettings() {
+ updateSecurityConfig(true, false)
+ startServer { serverId ->
+ val (encryptOnlySocket, connection) =
+ createConnectAcceptSocketUsingSettings(serverId, TEST_UUID, true, false)
+
+ val data: ByteArray =
+ "Test data for clientSendDataOverEncryptedOnlySocketUsingSocketSettings"
+ .toByteArray()
+ val socketOs = encryptOnlySocket.outputStream
+
+ socketOs.write(data)
+ val rxResponse: RfcommProto.RxResponse =
+ mBumble
+ .rfcommBlocking()
+ .withDeadlineAfter(GRPC_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
+ .receive(RfcommProto.RxRequest.newBuilder().setConnection(connection).build())
+ Truth.assertThat(rxResponse.data).isEqualTo(ByteString.copyFrom(data))
+ }
+ }
+
+ /*
+ Test Steps:
+ 1. Create an secure socket
+ 2. Connect to the socket
+ 3. Verify that devices are connected
+ 4. Write data to socket output stream
+ 5. Verify bumble received that data
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_SOCKET_SETTINGS_API)
+ fun clientSendDataOverSecureSocketUsingSocketSettings() {
+ updateSecurityConfig(true, true)
+ startServer { serverId ->
+ val (secureSocket, connection) =
+ createConnectAcceptSocketUsingSettings(serverId, TEST_UUID, true, false)
+ val data: ByteArray =
+ "Test data for clientSendDataOverSecureSocketUsingSocketSettings".toByteArray()
+ val socketOs = secureSocket.outputStream
+
+ socketOs.write(data)
+ val rxResponse: RfcommProto.RxResponse =
+ mBumble
+ .rfcommBlocking()
+ .withDeadlineAfter(GRPC_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
+ .receive(RfcommProto.RxRequest.newBuilder().setConnection(connection).build())
+ Truth.assertThat(rxResponse.data).isEqualTo(ByteString.copyFrom(data))
+ }
+ }
+
+ // helper to update the security config for remote bumble device
+ private fun updateSecurityConfig(
+ isEncrypted: Boolean = false,
+ isAuthenticated: Boolean = false,
+ ) {
+ val pairingConfig =
+ BumbleConfigProto.PairingConfig.newBuilder()
+ .setBonding(isEncrypted)
+ .setMitm(isAuthenticated)
+ .setSc(isEncrypted)
+ .setIdentityAddressType(HostProto.OwnAddressType.PUBLIC)
+ .build()
+ val overrideRequest =
+ BumbleConfigProto.OverrideRequest.newBuilder().setPairingConfig(pairingConfig).build()
+ mBumble.bumbleConfigBlocking().override(overrideRequest)
+ }
+
+ private fun createConnectAcceptSocketUsingSettings(
+ server: ServerId,
+ uuid: String = TEST_UUID,
+ isEncrypted: Boolean = false,
+ isAuthenticated: Boolean = false,
+ ): Pair<BluetoothSocket, RfcommProto.RfcommConnection> {
+ val socket =
+ createClientSocketUsingSocketSettings(uuid, mRemoteDevice, isEncrypted, isAuthenticated)
+
+ val connection = acceptSocket(server)
+
+ Truth.assertThat(socket.isConnected).isTrue()
+
+ return Pair(socket, connection)
+ }
+
private fun createConnectAcceptSocket(
isSecure: Boolean,
server: ServerId,
@@ -475,6 +598,47 @@ class RfcommTest {
return Pair(socket, connection)
}
+ private fun createClientSocketUsingSocketSettings(
+ uuid: String,
+ remoteDevice: BluetoothDevice,
+ isEncrypted: Boolean = false,
+ isAuthenticated: Boolean = false,
+ ): BluetoothSocket {
+ var socket: BluetoothSocket
+
+ socket =
+ remoteDevice.createUsingSocketSettings(
+ BluetoothSocketSettings.Builder()
+ .setSocketType(BluetoothSocket.TYPE_RFCOMM)
+ .setEncryptionRequired(isEncrypted)
+ .setAuthenticationRequired(isAuthenticated)
+ .setRfcommUuid(UUID.fromString(uuid))
+ .build()
+ )
+
+ runBlocking(mScope.coroutineContext) {
+ withTimeout(CONNECT_TIMEOUT.toMillis()) {
+ // We need to reply to the pairing request in the case where the devices aren't
+ // bonded yet
+ if (
+ (isEncrypted || isAuthenticated) &&
+ !mAdapter.bondedDevices.contains(remoteDevice)
+ ) {
+ launch {
+ Log.i(TAG, "Waiting for ACTION_PAIRING_REQUEST")
+ mFlow
+ .filter { it.action == BluetoothDevice.ACTION_PAIRING_REQUEST }
+ .filter { it.getBluetoothDeviceExtra() == remoteDevice }
+ .first()
+ remoteDevice.setPairingConfirmation(true)
+ }
+ }
+ socket.connect()
+ }
+ }
+ return socket
+ }
+
private fun createSocket(
device: BluetoothDevice,
isSecure: Boolean,
diff --git a/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java b/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java
new file mode 100644
index 0000000000..b879053de8
--- /dev/null
+++ b/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.hid;
+
+import static android.bluetooth.BluetoothDevice.TRANSPORT_BREDR;
+import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING;
+
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.oneOf;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHidHost;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
+import android.bluetooth.Host;
+import android.bluetooth.PandoraDevice;
+import android.bluetooth.test_utils.EnableBluetoothRule;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ParcelUuid;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.bluetooth.flags.Flags;
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+
+import org.hamcrest.CustomTypeSafeMatcher;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.hamcrest.core.AllOf;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.hamcrest.MockitoHamcrest;
+
+import pandora.GattProto;
+import pandora.GattProto.GattCharacteristicParams;
+import pandora.HIDGrpc;
+import pandora.HidProto.HidServiceType;
+import pandora.HidProto.ServiceRequest;
+import pandora.HostProto.AdvertiseRequest;
+import pandora.HostProto.DiscoverabilityMode;
+import pandora.HostProto.OwnAddressType;
+import pandora.HostProto.SetDiscoverabilityModeRequest;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class HidHeadTrackerTest {
+ private static final String TAG = HidHeadTrackerTest.class.getSimpleName();
+ private static final String BUMBLE_DEVICE_NAME = "Bumble";
+ private static final Duration BOND_INTENT_TIMEOUT = Duration.ofSeconds(10);
+ private static final Duration INTENT_TIMEOUT = Duration.ofSeconds(10);
+ private static final int DISCOVERY_TIMEOUT = 2000; // 2 seconds
+ private CompletableFuture<BluetoothDevice> mDeviceFound;
+ private static final ParcelUuid HEADTRACKER_UUID =
+ ParcelUuid.fromString("109b862f-50e3-45cc-8ea1-ac62de4846d1");
+ private static final ParcelUuid HEADTRACKER_VERSION_CHARACTERISTIC_UUID =
+ ParcelUuid.fromString("b4eb9919-a910-46a2-a9dd-fec2525196fd");
+ private static final ParcelUuid HEADTRACKER_CONTROL_CHARACTERISTIC_UUID =
+ ParcelUuid.fromString("8584cbb5-2d58-45a3-ab9d-583e0958b067");
+ private static final ParcelUuid HEADTRACKER_REPORT_CHARACTERISTIC_UUID =
+ ParcelUuid.fromString("e66dd173-b2ae-4f5a-ae16-0162af8038ae");
+
+ private static final Context sTargetContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final BluetoothAdapter sAdapter =
+ sTargetContext.getSystemService(BluetoothManager.class).getAdapter();
+ private HIDGrpc.HIDBlockingStub mHidBlockingStub;
+
+ @Rule(order = 0)
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ @Rule(order = 1)
+ public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
+
+ @Rule(order = 2)
+ public final PandoraDevice mBumble = new PandoraDevice();
+
+ @Rule(order = 3)
+ public final EnableBluetoothRule mEnableBluetoothRule =
+ new EnableBluetoothRule(false /* enableTestMode */, true /* toggleBluetooth */);
+
+ @Mock private BroadcastReceiver mReceiver;
+ @Mock private BluetoothProfile.ServiceListener mProfileServiceListener;
+ private final Map<String, Integer> mActionRegistrationCounts = new HashMap<>();
+ private InOrder mInOrder = null;
+ private BluetoothDevice mBumbleDevice;
+ private Host mHost;
+ private BluetoothHidHost mHidService;
+ private BluetoothHeadset mHfpService;
+ private BluetoothA2dp mA2dpService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mHidBlockingStub = mBumble.hidBlocking();
+
+ doAnswer(
+ inv -> {
+ Log.d(
+ TAG,
+ "onReceive(): intent=" + Arrays.toString(inv.getArguments()));
+ Intent intent = inv.getArgument(1);
+ String action = intent.getAction();
+ if (BluetoothDevice.ACTION_UUID.equals(action)) {
+ ParcelUuid[] uuids =
+ intent.getParcelableArrayExtra(
+ BluetoothDevice.EXTRA_UUID, ParcelUuid.class);
+ Log.d(TAG, "onReceive(): UUID=" + Arrays.toString(uuids));
+ } else if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
+ BluetoothDevice device =
+ intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE,
+ BluetoothDevice.class);
+ String deviceName =
+ String.valueOf(
+ intent.getStringExtra(BluetoothDevice.EXTRA_NAME));
+ Log.i(
+ TAG,
+ "Discovered device: "
+ + device
+ + " with name: "
+ + deviceName);
+ if (deviceName != null && BUMBLE_DEVICE_NAME.equals(deviceName)) {
+ if (mDeviceFound != null) {
+ mDeviceFound.complete(device);
+ }
+ }
+ } else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(
+ intent.getAction())) {
+ BluetoothDevice device =
+ intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE,
+ BluetoothDevice.class);
+ int transport =
+ intent.getIntExtra(
+ BluetoothDevice.EXTRA_TRANSPORT,
+ BluetoothDevice.TRANSPORT_AUTO);
+ Log.i(
+ TAG,
+ "ACL connected for device="
+ + device
+ + " with transport: "
+ + transport);
+ } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(
+ intent.getAction())) {
+ BluetoothDevice device =
+ intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE,
+ BluetoothDevice.class);
+ int transport =
+ intent.getIntExtra(
+ BluetoothDevice.EXTRA_TRANSPORT,
+ BluetoothDevice.TRANSPORT_AUTO);
+ Log.i(
+ TAG,
+ "ACL Disconnected for device="
+ + device
+ + " with transport: "
+ + transport);
+ } else if (BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED.equals(
+ intent.getAction())) {
+ BluetoothDevice device =
+ intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE,
+ BluetoothDevice.class);
+ int state =
+ intent.getIntExtra(
+ BluetoothProfile.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ int transport =
+ intent.getIntExtra(
+ BluetoothDevice.EXTRA_TRANSPORT,
+ BluetoothDevice.TRANSPORT_AUTO);
+ Log.i(
+ TAG,
+ "Connection state change: device="
+ + device
+ + " "
+ + BluetoothProfile.getConnectionStateName(state)
+ + "("
+ + state
+ + "), transport: "
+ + transport);
+ }
+ return null;
+ })
+ .when(mReceiver)
+ .onReceive(any(), any());
+
+ mInOrder = inOrder(mReceiver);
+ mHost = new Host(sTargetContext);
+ // Get profile proxies
+ sAdapter.getProfileProxy(
+ sTargetContext, mProfileServiceListener, BluetoothProfile.HID_HOST);
+ mHidService = (BluetoothHidHost) verifyProfileServiceConnected(BluetoothProfile.HID_HOST);
+ sAdapter.getProfileProxy(sTargetContext, mProfileServiceListener, BluetoothProfile.A2DP);
+ mA2dpService = (BluetoothA2dp) verifyProfileServiceConnected(BluetoothProfile.A2DP);
+ sAdapter.getProfileProxy(sTargetContext, mProfileServiceListener, BluetoothProfile.HEADSET);
+ mHfpService = (BluetoothHeadset) verifyProfileServiceConnected(BluetoothProfile.HEADSET);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if ((mBumbleDevice != null)
+ && mBumbleDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
+ mHost.removeBondAndVerify(mBumbleDevice);
+ }
+ mHost.close();
+ mBumbleDevice = null;
+ if (getTotalActionRegistrationCounts() > 0) {
+ sTargetContext.unregisterReceiver(mReceiver);
+ mActionRegistrationCounts.clear();
+ }
+ }
+
+ /**
+ * Ensure that successful HID connection over LE Transport.
+ *
+ * <p>Prerequisites:
+ *
+ * <ol>
+ * <li>Bumble has Android Headtracker Service
+ * <li>Bumble does not support HID and HOGP
+ * <li>Bummble is connectable over LE
+ * </ol>
+ *
+ * <p>Steps:
+ *
+ * <ol>
+ * <li>Android pairs with Bumble
+ * <li>Android Bluetooth reports HID host connection
+ * <li>Disconnect and reconnect
+ * <li>Android Bluetooth reports HID host connection
+ * </ol>
+ *
+ * Expectation: successful HID connection over LE Transport
+ */
+ @SuppressLint("MissingPermission")
+ @Test
+ @RequiresFlagsEnabled({
+ Flags.FLAG_ALLOW_SWITCHING_HID_AND_HOGP,
+ Flags.FLAG_SAVE_INITIAL_HID_CONNECTION_POLICY
+ })
+ public void connectWithoutHidServiceTest() {
+
+ registerIntentActions(
+ BluetoothDevice.ACTION_ACL_CONNECTED,
+ BluetoothDevice.ACTION_ACL_DISCONNECTED,
+ BluetoothDevice.ACTION_UUID,
+ BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED,
+ BluetoothDevice.ACTION_FOUND);
+
+ pairAndConnect();
+ // Verify ACL connection on classic transport first and then LE transport
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_ACL_CONNECTED),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_BREDR));
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_ACL_CONNECTED),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE));
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_UUID),
+ hasExtra(BluetoothDevice.EXTRA_UUID, Matchers.hasItemInArray(HEADTRACKER_UUID)));
+
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_LE), equalTo(STATE_CONNECTING));
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_LE), equalTo(STATE_CONNECTED));
+
+ // Disable a2dp and HFP connetcion policy
+
+ if (mA2dpService.getConnectionPolicy(mBumbleDevice)
+ == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ assertThat(
+ mA2dpService.setConnectionPolicy(
+ mBumbleDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN))
+ .isTrue();
+ }
+ if (mHfpService.getConnectionPolicy(mBumbleDevice)
+ == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ assertThat(
+ mHfpService.setConnectionPolicy(
+ mBumbleDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN))
+ .isTrue();
+ }
+
+ // Disconnect and Reconnect
+ assertThat(mBumbleDevice.disconnect()).isEqualTo(BluetoothStatusCodes.SUCCESS);
+
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_LE), equalTo(STATE_DISCONNECTING));
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_LE), equalTo(STATE_DISCONNECTED));
+ // Wait for ACL to get disconnected
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_ACL_DISCONNECTED),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice));
+
+ assertThat(mBumbleDevice.connect()).isEqualTo(BluetoothStatusCodes.SUCCESS);
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_LE), equalTo(STATE_CONNECTING));
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_ACL_CONNECTED),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice));
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_LE), equalTo(STATE_CONNECTED));
+ unregisterIntentActions(
+ BluetoothDevice.ACTION_UUID,
+ BluetoothDevice.ACTION_ACL_CONNECTED,
+ BluetoothDevice.ACTION_ACL_DISCONNECTED,
+ BluetoothDevice.ACTION_FOUND);
+ }
+
+ /**
+ * Ensure that successful HID connection over BREDR Transport.
+ *
+ * <p>Prerequisites:
+ *
+ * <ol>
+ * <li>Bumble has Android Headtracker Service
+ * <li>Bumble supports only HID but not HOGP
+ * <li>Bummble is connectable over LE
+ * </ol>
+ *
+ * <p>Steps:
+ *
+ * <ol>
+ * <li>Android pairs with Bumble
+ * <li>Android Bluetooth reports HID host connection
+ * <li>Change the preferred transport to LE
+ * <li>Android Bluetooth reports HID host connection over LE
+ * </ol>
+ *
+ * Expectation: successful HID connection over BREDR Transport and Preferred transport selection
+ * success
+ */
+ @SuppressLint("MissingPermission")
+ @Test
+ @RequiresFlagsEnabled({
+ Flags.FLAG_ALLOW_SWITCHING_HID_AND_HOGP,
+ Flags.FLAG_SAVE_INITIAL_HID_CONNECTION_POLICY
+ })
+ public void connectWithHidServiceTest() {
+
+ registerIntentActions(
+ BluetoothDevice.ACTION_ACL_CONNECTED,
+ BluetoothDevice.ACTION_UUID,
+ BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED,
+ BluetoothDevice.ACTION_FOUND);
+ mHidBlockingStub.registerService(
+ ServiceRequest.newBuilder()
+ .setServiceType(HidServiceType.SERVICE_TYPE_HID)
+ .build());
+ pairAndConnect();
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_UUID),
+ hasExtra(BluetoothDevice.EXTRA_UUID, Matchers.hasItemInArray(HEADTRACKER_UUID)));
+
+ verifyConnectionState(mBumbleDevice, equalTo(TRANSPORT_BREDR), equalTo(STATE_CONNECTED));
+ // Switch to LE Transport
+ mHidService.setPreferredTransport(mBumbleDevice, TRANSPORT_LE);
+ verifyTransportSwitch(mBumbleDevice, TRANSPORT_BREDR, TRANSPORT_LE);
+
+ unregisterIntentActions(
+ BluetoothDevice.ACTION_UUID,
+ BluetoothDevice.ACTION_ACL_CONNECTED,
+ BluetoothDevice.ACTION_FOUND);
+ }
+
+ private void pairAndConnect() {
+
+ // Register Head tracker services on Bumble
+ GattCharacteristicParams characteristicVersion =
+ GattCharacteristicParams.newBuilder()
+ .setProperties(
+ BluetoothGattCharacteristic.PROPERTY_READ
+ | BluetoothGattCharacteristic.PROPERTY_WRITE)
+ .setUuid(HEADTRACKER_VERSION_CHARACTERISTIC_UUID.toString())
+ .build();
+
+ GattCharacteristicParams characteristicControl =
+ GattCharacteristicParams.newBuilder()
+ .setProperties(
+ BluetoothGattCharacteristic.PROPERTY_READ
+ | BluetoothGattCharacteristic.PROPERTY_WRITE)
+ .setUuid(HEADTRACKER_CONTROL_CHARACTERISTIC_UUID.toString())
+ .build();
+ GattCharacteristicParams characteristicReport =
+ GattCharacteristicParams.newBuilder()
+ .setProperties(
+ BluetoothGattCharacteristic.PROPERTY_READ
+ | BluetoothGattCharacteristic.PROPERTY_WRITE)
+ .setUuid(HEADTRACKER_REPORT_CHARACTERISTIC_UUID.toString())
+ .build();
+ mBumble.gattBlocking()
+ .registerService(
+ GattProto.RegisterServiceRequest.newBuilder()
+ .setService(
+ GattProto.GattServiceParams.newBuilder()
+ .addCharacteristics(characteristicVersion)
+ .addCharacteristics(characteristicControl)
+ .addCharacteristics(characteristicReport)
+ .setUuid(HEADTRACKER_UUID.toString())
+ .build())
+ .build());
+
+ // Make Bumble connectable
+ mBumble.hostBlocking()
+ .advertise(
+ AdvertiseRequest.newBuilder()
+ .setLegacy(true)
+ .setConnectable(true)
+ .setOwnAddressType(OwnAddressType.RANDOM)
+ .build());
+ // Make Bumble discoverable over BR/EDR
+ mBumble.hostBlocking()
+ .setDiscoverabilityMode(
+ SetDiscoverabilityModeRequest.newBuilder()
+ .setMode(DiscoverabilityMode.DISCOVERABLE_GENERAL)
+ .build());
+ // Start Discovery
+ mDeviceFound = new CompletableFuture<>();
+ assertThat(sAdapter.startDiscovery()).isTrue();
+ mBumbleDevice =
+ mDeviceFound
+ .completeOnTimeout(null, DISCOVERY_TIMEOUT, TimeUnit.MILLISECONDS)
+ .join();
+ assertThat(sAdapter.cancelDiscovery()).isTrue();
+ // Create Bond
+ mHost.createBondAndVerify(mBumbleDevice);
+ }
+
+ /**
+ * CONNECTING and DISCONNECTING intents can go out of order, hence need a special function to
+ * verify transport switches if we want to verify connecting and disconnected states
+ *
+ * <p>Four intents are expected: 1. fromTransport DISCONNECTING 2. toTransport CONNECTING 3.
+ * fromTransport DISCONNECTED 4. toTransport CONNECTED
+ *
+ * <p>Currently, the order of 2 and 3 is unstable and hence we need this method to work with
+ * both 2 -> 3 AND 3 -> 2
+ *
+ * <p>This function is complicated because we cannot mix ordered verification and unordered
+ * verification if the same set of argument will appear more than once.
+ *
+ * @param device target dual mode HID device
+ * @param fromTransport from which transport
+ * @param toTransport to which transport
+ */
+ private void verifyTransportSwitch(BluetoothDevice device, int fromTransport, int toTransport) {
+ assertThat(fromTransport).isNotEqualTo(toTransport);
+ verifyConnectionState(mBumbleDevice, equalTo(fromTransport), equalTo(STATE_DISCONNECTING));
+
+ // Capture the next intent with filter
+ // Filter is necessary as otherwise it will corrupt all other unordered verifications
+ final Intent[] savedIntent = {null};
+ verifyIntentReceived(
+ new CustomTypeSafeMatcher<>("Intent Matcher") {
+ public boolean matchesSafely(Intent intent) {
+ savedIntent[0] = intent;
+ return AllOf.allOf(
+ hasAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
+ hasExtra(
+ BluetoothDevice.EXTRA_TRANSPORT,
+ oneOf(fromTransport, toTransport)),
+ hasExtra(
+ BluetoothProfile.EXTRA_STATE,
+ oneOf(STATE_CONNECTING, STATE_DISCONNECTED)))
+ .matches(intent);
+ }
+ });
+
+ // Verify saved intent is correct
+ assertThat(savedIntent[0]).isNotNull();
+ Intent intent = savedIntent[0];
+ assertThat(intent.getAction()).isNotNull();
+ assertThat(intent.getAction()).isEqualTo(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
+ assertThat(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice.class))
+ .isEqualTo(device);
+ assertThat(intent.hasExtra(BluetoothProfile.EXTRA_STATE)).isTrue();
+ int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, STATE_CONNECTED);
+ assertThat(state).isAnyOf(STATE_CONNECTING, STATE_DISCONNECTED);
+ assertThat(intent.hasExtra(BluetoothDevice.EXTRA_TRANSPORT)).isTrue();
+ int transport =
+ intent.getIntExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_AUTO);
+ assertThat(transport).isAnyOf(TRANSPORT_BREDR, TRANSPORT_LE);
+
+ // Conditionally verify the next intent
+ if (transport == fromTransport) {
+ assertThat(state).isEqualTo(STATE_DISCONNECTED);
+ verifyConnectionState(mBumbleDevice, equalTo(toTransport), equalTo(STATE_CONNECTING));
+ } else {
+ assertThat(state).isEqualTo(STATE_CONNECTING);
+ verifyConnectionState(
+ mBumbleDevice, equalTo(fromTransport), equalTo(STATE_DISCONNECTED));
+ }
+ verifyConnectionState(mBumbleDevice, equalTo(toTransport), equalTo(STATE_CONNECTED));
+ }
+
+ @SafeVarargs
+ private void verifyIntentReceived(Matcher<Intent>... matchers) {
+ mInOrder.verify(mReceiver, timeout(BOND_INTENT_TIMEOUT.toMillis()))
+ .onReceive(any(Context.class), MockitoHamcrest.argThat(AllOf.allOf(matchers)));
+ }
+
+ private void verifyConnectionState(
+ BluetoothDevice device, Matcher<Integer> transport, Matcher<Integer> state) {
+
+ verifyIntentReceived(
+ hasAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, transport),
+ hasExtra(BluetoothProfile.EXTRA_STATE, state));
+ }
+
+ /**
+ * Helper function to add reference count to registered intent actions
+ *
+ * @param actions new intent actions to add. If the array is empty, it is a no-op.
+ */
+ private void registerIntentActions(String... actions) {
+ if (actions.length == 0) {
+ return;
+ }
+ if (getTotalActionRegistrationCounts() > 0) {
+ Log.d(TAG, "registerIntentActions(): unregister ALL intents");
+ sTargetContext.unregisterReceiver(mReceiver);
+ }
+ for (String action : actions) {
+ mActionRegistrationCounts.merge(action, 1, Integer::sum);
+ }
+ IntentFilter filter = new IntentFilter();
+ mActionRegistrationCounts.entrySet().stream()
+ .filter(entry -> entry.getValue() > 0)
+ .forEach(
+ entry -> {
+ Log.d(
+ TAG,
+ "registerIntentActions(): Registering action = "
+ + entry.getKey());
+ filter.addAction(entry.getKey());
+ });
+ sTargetContext.registerReceiver(mReceiver, filter);
+ }
+
+ /**
+ * Helper function to reduce reference count to registered intent actions If total reference
+ * count is zero after removal, no broadcast receiver will be registered.
+ *
+ * @param actions intent actions to be removed. If some action is not registered, it is no-op
+ * for that action. If the actions array is empty, it is also a no-op.
+ */
+ private void unregisterIntentActions(String... actions) {
+ if (actions.length == 0) {
+ return;
+ }
+ if (getTotalActionRegistrationCounts() <= 0) {
+ return;
+ }
+ Log.d(TAG, "unregisterIntentActions(): unregister ALL intents");
+ sTargetContext.unregisterReceiver(mReceiver);
+ for (String action : actions) {
+ if (!mActionRegistrationCounts.containsKey(action)) {
+ continue;
+ }
+ mActionRegistrationCounts.put(action, mActionRegistrationCounts.get(action) - 1);
+ if (mActionRegistrationCounts.get(action) <= 0) {
+ mActionRegistrationCounts.remove(action);
+ }
+ }
+ if (getTotalActionRegistrationCounts() > 0) {
+ IntentFilter filter = new IntentFilter();
+ mActionRegistrationCounts.entrySet().stream()
+ .filter(entry -> entry.getValue() > 0)
+ .forEach(
+ entry -> {
+ Log.d(
+ TAG,
+ "unregisterIntentActions(): Registering action = "
+ + entry.getKey());
+ filter.addAction(entry.getKey());
+ });
+ sTargetContext.registerReceiver(mReceiver, filter);
+ }
+ }
+
+ /**
+ * Get sum of reference count from all registered actions
+ *
+ * @return sum of reference count from all registered actions
+ */
+ private int getTotalActionRegistrationCounts() {
+ return mActionRegistrationCounts.values().stream().reduce(0, Integer::sum);
+ }
+
+ private BluetoothProfile verifyProfileServiceConnected(int profile) {
+ ArgumentCaptor<BluetoothProfile> proxyCaptor =
+ ArgumentCaptor.forClass(BluetoothProfile.class);
+ verify(mProfileServiceListener, timeout(INTENT_TIMEOUT.toMillis()))
+ .onServiceConnected(eq(profile), proxyCaptor.capture());
+ return proxyCaptor.getValue();
+ }
+}
diff --git a/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java b/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java
index cddee2a9ad..3d7587c5c8 100644
--- a/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java
@@ -84,6 +84,9 @@ import org.mockito.MockitoAnnotations;
import org.mockito.hamcrest.MockitoHamcrest;
import org.mockito.stubbing.Answer;
+import pandora.HIDGrpc;
+import pandora.HidProto.HidServiceType;
+import pandora.HidProto.ServiceRequest;
import pandora.HostProto.AdvertiseRequest;
import pandora.HostProto.OwnAddressType;
@@ -108,6 +111,7 @@ public class HidHostDualModeTest {
InstrumentationRegistry.getInstrumentation().getTargetContext();
private final BluetoothAdapter mAdapter =
mContext.getSystemService(BluetoothManager.class).getAdapter();
+ private HIDGrpc.HIDBlockingStub mHidBlockingStub;
@Rule(order = 0)
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -275,6 +279,11 @@ public class HidHostDualModeTest {
BluetoothHeadset hfpService =
(BluetoothHeadset) verifyProfileServiceConnected(BluetoothProfile.HEADSET);
+ mHidBlockingStub = mBumble.hidBlocking();
+ mHidBlockingStub.registerService(
+ ServiceRequest.newBuilder()
+ .setServiceType(HidServiceType.SERVICE_TYPE_BOTH)
+ .build());
AdvertiseRequest request =
AdvertiseRequest.newBuilder()
.setLegacy(true)
diff --git a/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java b/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java
index 76eda63d41..a4e61aa198 100644
--- a/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/hid/HidHostTest.java
@@ -81,8 +81,10 @@ import org.mockito.hamcrest.MockitoHamcrest;
import org.mockito.stubbing.Answer;
import pandora.HIDGrpc;
+import pandora.HidProto.HidServiceType;
import pandora.HidProto.ProtocolModeEvent;
import pandora.HidProto.ReportEvent;
+import pandora.HidProto.ServiceRequest;
import java.time.Duration;
import java.util.Arrays;
@@ -286,7 +288,10 @@ public class HidHostTest {
(BluetoothHeadset) verifyProfileServiceConnected(BluetoothProfile.HEADSET);
mHidBlockingStub = mBumble.hidBlocking();
-
+ mHidBlockingStub.registerService(
+ ServiceRequest.newBuilder()
+ .setServiceType(HidServiceType.SERVICE_TYPE_HID)
+ .build());
mDevice = mBumble.getRemoteDevice();
// Remove bond if the device is already bonded
if (mDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
@@ -662,6 +667,12 @@ public class HidHostTest {
mHidBlockingStub
.withDeadlineAfter(PROTO_MODE_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
.onSetReport(Empty.getDefaultInstance());
+
+ // Todo: as a workaround added 50ms delay.
+ // To be removed once root cause is identified for b/382180335
+ final CompletableFuture<Integer> future = new CompletableFuture<>();
+ future.completeOnTimeout(null, 50, TimeUnit.MILLISECONDS).join();
+
// Keyboard report
String kbReportData = "010203040506070809";
mHidService.setReport(mDevice, BluetoothHidHost.REPORT_TYPE_INPUT, kbReportData);
diff --git a/framework/tests/bumble/src/android/bluetooth/pairing/EncryptionChangeTest.java b/framework/tests/bumble/src/android/bluetooth/pairing/EncryptionChangeTest.java
new file mode 100644
index 0000000000..ce508aebb3
--- /dev/null
+++ b/framework/tests/bumble/src/android/bluetooth/pairing/EncryptionChangeTest.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.pairing;
+
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHidHost;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.PandoraDevice;
+import android.bluetooth.StreamObserverSpliterator;
+import android.bluetooth.test_utils.EnableBluetoothRule;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ParcelUuid;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.bluetooth.flags.Flags;
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+
+import io.grpc.stub.StreamObserver;
+
+import org.hamcrest.Matcher;
+import org.hamcrest.core.AllOf;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.hamcrest.MockitoHamcrest;
+
+import pandora.GattProto;
+import pandora.HostProto.AdvertiseRequest;
+import pandora.HostProto.OwnAddressType;
+import pandora.SecurityProto.PairingEvent;
+import pandora.SecurityProto.PairingEventAnswer;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class EncryptionChangeTest {
+ private static final String TAG = "EncryptionChangeTest";
+ private static final Duration BOND_INTENT_TIMEOUT = Duration.ofSeconds(10);
+
+ private static final ParcelUuid BATTERY_UUID =
+ ParcelUuid.fromString("0000180F-0000-1000-8000-00805F9B34FB");
+
+ private static final ParcelUuid HOGP_UUID =
+ ParcelUuid.fromString("00001812-0000-1000-8000-00805F9B34FB");
+
+ private static final Context sTargetContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final BluetoothAdapter sAdapter =
+ sTargetContext.getSystemService(BluetoothManager.class).getAdapter();
+
+ @Rule(order = 0)
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ @Rule(order = 1)
+ public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
+
+ @Rule(order = 2)
+ public final PandoraDevice mBumble = new PandoraDevice();
+
+ @Rule(order = 3)
+ public final EnableBluetoothRule mEnableBluetoothRule =
+ new EnableBluetoothRule(false /* enableTestMode */, true /* toggleBluetooth */);
+
+ private final Map<String, Integer> mActionRegistrationCounts = new HashMap<>();
+ private final StreamObserverSpliterator<PairingEvent> mPairingEventStreamObserver =
+ new StreamObserverSpliterator<>();
+ @Mock private BroadcastReceiver mReceiver;
+ @Mock private BluetoothProfile.ServiceListener mProfileServiceListener;
+ private InOrder mInOrder = null;
+ private BluetoothDevice mBumbleDevice;
+ private BluetoothHidHost mHidService;
+ private BluetoothHeadset mHfpService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer(
+ inv -> {
+ Log.d(
+ TAG,
+ "onReceive(): intent=" + Arrays.toString(inv.getArguments()));
+ Intent intent = inv.getArgument(1);
+ String action = intent.getAction();
+ if (BluetoothDevice.ACTION_UUID.equals(action)) {
+ ParcelUuid[] uuids =
+ intent.getParcelableArrayExtra(
+ BluetoothDevice.EXTRA_UUID, ParcelUuid.class);
+ Log.d(TAG, "onReceive(): UUID=" + Arrays.toString(uuids));
+ } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
+ int bondState =
+ intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
+ Log.d(TAG, "onReceive(): bondState=" + bondState);
+ }
+ return null;
+ })
+ .when(mReceiver)
+ .onReceive(any(), any());
+
+ mInOrder = inOrder(mReceiver);
+
+ // Get profile proxies
+ mHidService = (BluetoothHidHost) getProfileProxy(BluetoothProfile.HID_HOST);
+ mHfpService = (BluetoothHeadset) getProfileProxy(BluetoothProfile.HEADSET);
+
+ mBumbleDevice = mBumble.getRemoteDevice();
+ Set<BluetoothDevice> bondedDevices = sAdapter.getBondedDevices();
+ if (bondedDevices.contains(mBumbleDevice)) {
+ removeBond(mBumbleDevice);
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Set<BluetoothDevice> bondedDevices = sAdapter.getBondedDevices();
+ if (bondedDevices.contains(mBumbleDevice)) {
+ removeBond(mBumbleDevice);
+ }
+ mBumbleDevice = null;
+ if (getTotalActionRegistrationCounts() > 0) {
+ sTargetContext.unregisterReceiver(mReceiver);
+ mActionRegistrationCounts.clear();
+ }
+ }
+
+ /**
+ * Test Encryption change event on LE Secure link:
+ *
+ * <ol>
+ * <li>1. Android initiate create bond over LE link
+ * <li>2. Android confirms the pairing via pairing request intent
+ * <li>3. Bumble confirms the pairing internally (optional, added only for test confirmation)
+ * <li>4. Android verifies Encryption change Intent and bonded intent
+ * </ol>
+ */
+ @Test
+ @RequiresFlagsEnabled({Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST})
+ public void encryptionChangeSecureLeLink() {
+ registerIntentActions(
+ BluetoothDevice.ACTION_BOND_STATE_CHANGED,
+ BluetoothDevice.ACTION_ENCRYPTION_CHANGE,
+ BluetoothDevice.ACTION_PAIRING_REQUEST);
+ mBumble.gattBlocking()
+ .registerService(
+ GattProto.RegisterServiceRequest.newBuilder()
+ .setService(
+ GattProto.GattServiceParams.newBuilder()
+ .setUuid(HOGP_UUID.toString())
+ .build())
+ .build());
+
+ mBumble.hostBlocking()
+ .advertise(
+ AdvertiseRequest.newBuilder()
+ .setLegacy(true)
+ .setConnectable(true)
+ .setOwnAddressType(OwnAddressType.PUBLIC)
+ .build());
+
+ StreamObserver<PairingEventAnswer> pairingEventAnswerObserver =
+ mBumble.security()
+ .withDeadlineAfter(BOND_INTENT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
+ .onPairing(mPairingEventStreamObserver);
+
+ assertThat(mBumbleDevice.createBond(BluetoothDevice.TRANSPORT_LE)).isTrue();
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING));
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_PAIRING_REQUEST),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(
+ BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_CONSENT));
+ mBumbleDevice.setPairingConfirmation(true);
+
+ PairingEvent pairingEvent = mPairingEventStreamObserver.iterator().next();
+ assertThat(pairingEvent.hasJustWorks()).isTrue();
+ pairingEventAnswerObserver.onNext(
+ PairingEventAnswer.newBuilder().setEvent(pairingEvent).setConfirm(true).build());
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_ENCRYPTION_CHANGE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE),
+ hasExtra(BluetoothDevice.EXTRA_ENCRYPTION_STATUS, 0),
+ hasExtra(BluetoothDevice.EXTRA_ENCRYPTION_ENABLED, true),
+ hasExtra(BluetoothDevice.EXTRA_KEY_SIZE, 16),
+ hasExtra(
+ BluetoothDevice.EXTRA_ENCRYPTION_ALGORITHM,
+ BluetoothDevice.ENCRYPTION_ALGORITHM_AES));
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED));
+
+ verifyNoMoreInteractions(mReceiver);
+
+ unregisterIntentActions(
+ BluetoothDevice.ACTION_BOND_STATE_CHANGED,
+ BluetoothDevice.ACTION_ENCRYPTION_CHANGE,
+ BluetoothDevice.ACTION_PAIRING_REQUEST);
+ }
+
+ /**
+ * Test Encryption change event on classic link:
+ *
+ * <ol>
+ * <li>1. Android initiate create bond over Classic link
+ * <li>2. Android confirms the pairing via pairing request intent
+ * <li>3. Bumble confirms the pairing internally (optional, added only for test confirmation)
+ * <li>4. Android verifies Encryption change Intent and bonded intent
+ * </ol>
+ */
+ @Test
+ @RequiresFlagsEnabled({Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST})
+ public void encryptionChangeSecureClassicLink() {
+ registerIntentActions(
+ BluetoothDevice.ACTION_BOND_STATE_CHANGED,
+ BluetoothDevice.ACTION_ENCRYPTION_CHANGE,
+ BluetoothDevice.ACTION_PAIRING_REQUEST);
+
+ StreamObserver<PairingEventAnswer> pairingEventAnswerObserver =
+ mBumble.security()
+ .withDeadlineAfter(BOND_INTENT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
+ .onPairing(mPairingEventStreamObserver);
+
+ assertThat(mBumbleDevice.createBond(BluetoothDevice.TRANSPORT_BREDR)).isTrue();
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING));
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_PAIRING_REQUEST),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(
+ BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_CONSENT));
+ mBumbleDevice.setPairingConfirmation(true);
+
+ PairingEvent pairingEvent = mPairingEventStreamObserver.iterator().next();
+ assertThat(pairingEvent.hasJustWorks()).isTrue();
+ pairingEventAnswerObserver.onNext(
+ PairingEventAnswer.newBuilder().setEvent(pairingEvent).setConfirm(true).build());
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_ENCRYPTION_CHANGE),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_BREDR),
+ hasExtra(BluetoothDevice.EXTRA_ENCRYPTION_STATUS, 0),
+ hasExtra(BluetoothDevice.EXTRA_ENCRYPTION_ENABLED, true),
+ hasExtra(BluetoothDevice.EXTRA_KEY_SIZE, 16),
+ hasExtra(
+ BluetoothDevice.EXTRA_ENCRYPTION_ALGORITHM,
+ BluetoothDevice.ENCRYPTION_ALGORITHM_AES));
+
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED));
+
+ verifyNoMoreInteractions(mReceiver);
+ unregisterIntentActions(
+ BluetoothDevice.ACTION_BOND_STATE_CHANGED,
+ BluetoothDevice.ACTION_ENCRYPTION_CHANGE,
+ BluetoothDevice.ACTION_PAIRING_REQUEST);
+ }
+
+ private void removeBond(BluetoothDevice device) {
+ registerIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+
+ assertThat(device.removeBond()).isTrue();
+ verifyIntentReceived(
+ hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE));
+
+ unregisterIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ }
+
+ @SafeVarargs
+ private void verifyIntentReceived(Matcher<Intent>... matchers) {
+ mInOrder.verify(mReceiver, timeout(BOND_INTENT_TIMEOUT.toMillis()))
+ .onReceive(any(Context.class), MockitoHamcrest.argThat(AllOf.allOf(matchers)));
+ }
+
+ @SafeVarargs
+ private void verifyIntentReceivedUnordered(int num, Matcher<Intent>... matchers) {
+ verify(mReceiver, timeout(BOND_INTENT_TIMEOUT.toMillis()).times(num))
+ .onReceive(any(Context.class), MockitoHamcrest.argThat(AllOf.allOf(matchers)));
+ }
+
+ @SafeVarargs
+ private void verifyIntentReceivedUnordered(Matcher<Intent>... matchers) {
+ verifyIntentReceivedUnordered(1, matchers);
+ }
+
+ /**
+ * Helper function to add reference count to registered intent actions
+ *
+ * @param actions new intent actions to add. If the array is empty, it is a no-op.
+ */
+ private void registerIntentActions(String... actions) {
+ if (actions.length == 0) {
+ return;
+ }
+ if (getTotalActionRegistrationCounts() > 0) {
+ Log.d(TAG, "registerIntentActions(): unregister ALL intents");
+ sTargetContext.unregisterReceiver(mReceiver);
+ }
+ for (String action : actions) {
+ mActionRegistrationCounts.merge(action, 1, Integer::sum);
+ }
+ IntentFilter filter = new IntentFilter();
+ mActionRegistrationCounts.entrySet().stream()
+ .filter(entry -> entry.getValue() > 0)
+ .forEach(
+ entry -> {
+ Log.d(
+ TAG,
+ "registerIntentActions(): Registering action = "
+ + entry.getKey());
+ filter.addAction(entry.getKey());
+ });
+ sTargetContext.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
+ }
+
+ /**
+ * Helper function to reduce reference count to registered intent actions If total reference
+ * count is zero after removal, no broadcast receiver will be registered.
+ *
+ * @param actions intent actions to be removed. If some action is not registered, it is no-op
+ * for that action. If the actions array is empty, it is also a no-op.
+ */
+ private void unregisterIntentActions(String... actions) {
+ if (actions.length == 0) {
+ return;
+ }
+ if (getTotalActionRegistrationCounts() <= 0) {
+ return;
+ }
+ Log.d(TAG, "unregisterIntentActions(): unregister ALL intents");
+ sTargetContext.unregisterReceiver(mReceiver);
+ for (String action : actions) {
+ if (!mActionRegistrationCounts.containsKey(action)) {
+ continue;
+ }
+ mActionRegistrationCounts.put(action, mActionRegistrationCounts.get(action) - 1);
+ if (mActionRegistrationCounts.get(action) <= 0) {
+ mActionRegistrationCounts.remove(action);
+ }
+ }
+ if (getTotalActionRegistrationCounts() > 0) {
+ IntentFilter filter = new IntentFilter();
+ mActionRegistrationCounts.entrySet().stream()
+ .filter(entry -> entry.getValue() > 0)
+ .forEach(
+ entry -> {
+ Log.d(
+ TAG,
+ "unregisterIntentActions(): Registering action = "
+ + entry.getKey());
+ filter.addAction(entry.getKey());
+ });
+ sTargetContext.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
+ }
+ }
+
+ /**
+ * Get sum of reference count from all registered actions
+ *
+ * @return sum of reference count from all registered actions
+ */
+ private int getTotalActionRegistrationCounts() {
+ return mActionRegistrationCounts.values().stream().reduce(0, Integer::sum);
+ }
+
+ private BluetoothProfile getProfileProxy(int profile) {
+ sAdapter.getProfileProxy(sTargetContext, mProfileServiceListener, profile);
+ ArgumentCaptor<BluetoothProfile> proxyCaptor =
+ ArgumentCaptor.forClass(BluetoothProfile.class);
+ verify(mProfileServiceListener, timeout(BOND_INTENT_TIMEOUT.toMillis()))
+ .onServiceConnected(eq(profile), proxyCaptor.capture());
+ return proxyCaptor.getValue();
+ }
+}
diff --git a/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java b/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java
index 72cc903319..44c6564803 100644
--- a/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevice.BluetoothAddress;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothManager;
@@ -39,6 +40,7 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.PandoraDevice;
import android.bluetooth.StreamObserverSpliterator;
+import android.bluetooth.Utils;
import android.bluetooth.test_utils.BlockingBluetoothAdapter;
import android.bluetooth.test_utils.EnableBluetoothRule;
import android.content.BroadcastReceiver;
@@ -51,12 +53,14 @@ import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Log;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bluetooth.flags.Flags;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
import io.grpc.stub.StreamObserver;
import org.hamcrest.Matcher;
@@ -76,7 +80,9 @@ import org.mockito.hamcrest.MockitoHamcrest;
import pandora.GattProto;
import pandora.HostProto.AdvertiseRequest;
import pandora.HostProto.AdvertiseResponse;
+import pandora.HostProto.ConnectabilityMode;
import pandora.HostProto.OwnAddressType;
+import pandora.HostProto.SetConnectabilityModeRequest;
import pandora.SecurityProto.LESecurityLevel;
import pandora.SecurityProto.PairingEvent;
import pandora.SecurityProto.PairingEventAnswer;
@@ -88,12 +94,14 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
+@RunWith(TestParameterInjector.class)
public class PairingTest {
private static final String TAG = "PairingTest";
private static final Duration BOND_INTENT_TIMEOUT = Duration.ofSeconds(10);
+ private static final int TEST_DELAY_MS = 1000;
private static final ParcelUuid BATTERY_UUID =
ParcelUuid.fromString("0000180F-0000-1000-8000-00805F9B34FB");
@@ -126,6 +134,7 @@ public class PairingTest {
@Mock private BluetoothProfile.ServiceListener mProfileServiceListener;
private InOrder mInOrder = null;
private BluetoothDevice mBumbleDevice;
+ private BluetoothDevice mRemoteLeDevice;
private BluetoothHidHost mHidService;
private BluetoothHeadset mHfpService;
@@ -162,9 +171,12 @@ public class PairingTest {
mHfpService = (BluetoothHeadset) getProfileProxy(BluetoothProfile.HEADSET);
mBumbleDevice = mBumble.getRemoteDevice();
- Set<BluetoothDevice> bondedDevices = sAdapter.getBondedDevices();
- if (bondedDevices.contains(mBumbleDevice)) {
- removeBond(mBumbleDevice);
+ mRemoteLeDevice =
+ sAdapter.getRemoteLeDevice(
+ Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
+
+ for (BluetoothDevice device : sAdapter.getBondedDevices()) {
+ removeBond(device);
}
}
@@ -174,7 +186,11 @@ public class PairingTest {
if (bondedDevices.contains(mBumbleDevice)) {
removeBond(mBumbleDevice);
}
+ if (bondedDevices.contains(mRemoteLeDevice)) {
+ removeBond(mRemoteLeDevice);
+ }
mBumbleDevice = null;
+ mRemoteLeDevice = null;
if (getTotalActionRegistrationCounts() > 0) {
sTargetContext.unregisterReceiver(mReceiver);
mActionRegistrationCounts.clear();
@@ -481,7 +497,7 @@ public class PairingTest {
public void testBondLe_Reconnect() {
registerIntentActions(BluetoothDevice.ACTION_ACL_CONNECTED);
- testStep_BondLe();
+ testStep_BondLe(mBumbleDevice, OwnAddressType.PUBLIC);
assertThat(sAdapter.getBondedDevices()).contains(mBumbleDevice);
testStep_restartBt();
@@ -513,7 +529,56 @@ public class PairingTest {
unregisterIntentActions(BluetoothDevice.ACTION_ACL_CONNECTED);
}
- private void testStep_BondLe() {
+ /**
+ * Test if bonded LE device's identity address and type can be read
+ *
+ * <p>Prerequisites:
+ *
+ * <ol>
+ * <li>Bumble and Android are not bonded
+ * </ol>
+ *
+ * <p>Steps:
+ *
+ * <ol>
+ * <li>Bumble is discoverable and connectable over LE
+ * <li>Bumble device's identity address and type unknown
+ * <li>Android pairs with Bumble over LE
+ * <li>Bumble device's identity address and type are retrievable
+ * </ol>
+ *
+ * <p>Expectation: Bumble device's identity address and type are present
+ */
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API)
+ public void testBondLe_identityAddressWithType(@TestParameter boolean isRandom) {
+ if (isRandom) {
+ doTestIdentityAddressWithType(mRemoteLeDevice, OwnAddressType.RANDOM);
+ } else {
+ doTestIdentityAddressWithType(mBumbleDevice, OwnAddressType.PUBLIC);
+ }
+ }
+
+ private void doTestIdentityAddressWithType(
+ BluetoothDevice device, OwnAddressType ownAddressType) {
+ BluetoothAddress identityAddress = device.getIdentityAddressWithType();
+ assertThat(identityAddress.getAddress()).isNull();
+ assertThat(identityAddress.getAddressType())
+ .isEqualTo(BluetoothDevice.ADDRESS_TYPE_UNKNOWN);
+
+ testStep_BondLe(device, ownAddressType);
+ assertThat(sAdapter.getBondedDevices()).contains(device);
+
+ identityAddress = device.getIdentityAddressWithType();
+ assertThat(identityAddress.getAddress()).isEqualTo(device.getAddress());
+ assertThat(identityAddress.getAddressType())
+ .isEqualTo(
+ ownAddressType == OwnAddressType.RANDOM
+ ? BluetoothDevice.ADDRESS_TYPE_RANDOM
+ : BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+ }
+
+ private void testStep_BondLe(BluetoothDevice device, OwnAddressType ownAddressType) {
registerIntentActions(
BluetoothDevice.ACTION_BOND_STATE_CHANGED,
BluetoothDevice.ACTION_ACL_CONNECTED,
@@ -541,7 +606,7 @@ public class PairingTest {
AdvertiseRequest.newBuilder()
.setLegacy(true)
.setConnectable(true)
- .setOwnAddressType(OwnAddressType.PUBLIC)
+ .setOwnAddressType(ownAddressType)
.build());
StreamObserver<PairingEventAnswer> pairingEventAnswerObserver =
@@ -549,25 +614,25 @@ public class PairingTest {
.withDeadlineAfter(BOND_INTENT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)
.onPairing(mPairingEventStreamObserver);
- assertThat(mBumbleDevice.createBond(BluetoothDevice.TRANSPORT_LE)).isTrue();
+ assertThat(device.createBond(BluetoothDevice.TRANSPORT_LE)).isTrue();
verifyIntentReceivedUnordered(
hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
- hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING));
verifyIntentReceived(
hasAction(BluetoothDevice.ACTION_ACL_CONNECTED),
- hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
hasExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE));
verifyIntentReceivedUnordered(
hasAction(BluetoothDevice.ACTION_PAIRING_REQUEST),
- hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
hasExtra(
BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_CONSENT));
// Approve pairing from Android
- assertThat(mBumbleDevice.setPairingConfirmation(true)).isTrue();
+ assertThat(device.setPairingConfirmation(true)).isTrue();
PairingEvent pairingEvent = mPairingEventStreamObserver.iterator().next();
assertThat(pairingEvent.hasJustWorks()).isTrue();
@@ -577,7 +642,7 @@ public class PairingTest {
// Ensure that pairing succeeds
verifyIntentReceived(
hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
- hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED));
unregisterIntentActions(
@@ -618,6 +683,11 @@ public class PairingTest {
assertThat(sAdapter.getBondedDevices()).contains(mBumbleDevice);
+ SetConnectabilityModeRequest request =
+ SetConnectabilityModeRequest.newBuilder()
+ .setMode(ConnectabilityMode.CONNECTABLE)
+ .build();
+ mBumble.hostBlocking().setConnectabilityMode(request);
assertThat(mBumbleDevice.connect()).isEqualTo(BluetoothStatusCodes.SUCCESS);
verifyIntentReceived(
hasAction(BluetoothDevice.ACTION_ACL_CONNECTED),
@@ -653,7 +723,7 @@ public class PairingTest {
registerIntentActions(
BluetoothDevice.ACTION_ACL_DISCONNECTED, BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- testStep_BondLe();
+ testStep_BondLe(mBumbleDevice, OwnAddressType.PUBLIC);
assertThat(sAdapter.getBondedDevices()).contains(mBumbleDevice);
assertThat(mBumbleDevice.removeBond()).isTrue();
@@ -748,7 +818,7 @@ public class PairingTest {
BluetoothDevice.ACTION_BOND_STATE_CHANGED,
BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
- testStep_BondLe();
+ testStep_BondLe(mBumbleDevice, OwnAddressType.PUBLIC);
assertThat(sAdapter.getBondedDevices()).contains(mBumbleDevice);
// Wait for profiles to get connected
@@ -845,6 +915,10 @@ public class PairingTest {
hasExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_CONNECTED),
hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice));
+ // Todo: b/382118305 - due to settings app interference, profile connection initiate twice
+ // after bonding. Introduced 1 second delay after first profile connection success
+ final CompletableFuture<Integer> future = new CompletableFuture<>();
+ future.completeOnTimeout(null, TEST_DELAY_MS, TimeUnit.MILLISECONDS).join();
// Disconnect all profiles
assertThat(mBumbleDevice.disconnect()).isEqualTo(BluetoothStatusCodes.SUCCESS);
verifyIntentReceived(
@@ -1031,7 +1105,7 @@ public class PairingTest {
assertThat(device.removeBond()).isTrue();
verifyIntentReceived(
hasAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED),
- hasExtra(BluetoothDevice.EXTRA_DEVICE, mBumbleDevice),
+ hasExtra(BluetoothDevice.EXTRA_DEVICE, device),
hasExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE));
unregisterIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
diff --git a/framework/tests/bumble/src/android/bluetooth/service_discovery/LeAudioServiceDiscoveryTest.java b/framework/tests/bumble/src/android/bluetooth/service_discovery/LeAudioServiceDiscoveryTest.java
index 2f6a56c134..b5757c310f 100644
--- a/framework/tests/bumble/src/android/bluetooth/service_discovery/LeAudioServiceDiscoveryTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/service_discovery/LeAudioServiceDiscoveryTest.java
@@ -271,13 +271,11 @@ public class LeAudioServiceDiscoveryTest {
BluetoothDevice.EXTRA_UUID,
Matchers.allOf(
Matchers.hasItemInArray(BluetoothUuid.HFP),
- Matchers.hasItemInArray(BluetoothUuid.HID),
Matchers.hasItemInArray(BluetoothUuid.A2DP_SOURCE),
Matchers.hasItemInArray(BluetoothUuid.A2DP_SINK),
Matchers.hasItemInArray(BluetoothUuid.AVRCP),
Matchers.hasItemInArray(BluetoothUuid.LE_AUDIO),
- Matchers.hasItemInArray(BluetoothUuid.BATTERY),
- Matchers.hasItemInArray(BluetoothUuid.HOGP))));
+ Matchers.hasItemInArray(BluetoothUuid.BATTERY))));
unregisterIntentActions(
BluetoothDevice.ACTION_UUID,
BluetoothDevice.ACTION_ACL_CONNECTED,
diff --git a/framework/tests/bumble/src/android/bluetooth/service_discovery/ServiceDiscoveryTest.java b/framework/tests/bumble/src/android/bluetooth/service_discovery/ServiceDiscoveryTest.java
index 8c59c37ec4..15a44c3f44 100644
--- a/framework/tests/bumble/src/android/bluetooth/service_discovery/ServiceDiscoveryTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/service_discovery/ServiceDiscoveryTest.java
@@ -38,6 +38,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.ParcelUuid;
+import android.os.Parcelable;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -115,10 +116,32 @@ public class ServiceDiscoveryTest {
Intent intent = inv.getArgument(1);
String action = intent.getAction();
if (BluetoothDevice.ACTION_UUID.equals(action)) {
- ParcelUuid[] uuids =
+ BluetoothDevice device =
+ intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE,
+ BluetoothDevice.class);
+ Parcelable[] uuidsRaw =
intent.getParcelableArrayExtra(
BluetoothDevice.EXTRA_UUID, ParcelUuid.class);
- Log.d(TAG, "onReceive(): UUID=" + Arrays.toString(uuids));
+ if (uuidsRaw == null) {
+ Log.e(TAG, "onReceive(): device " + device + " null uuid list");
+ } else if (uuidsRaw.length == 0) {
+ Log.e(
+ TAG,
+ "onReceive(): device "
+ + device
+ + " 0 length uuid list");
+ } else {
+ ParcelUuid[] uuids =
+ Arrays.copyOf(
+ uuidsRaw, uuidsRaw.length, ParcelUuid[].class);
+ Log.d(
+ TAG,
+ "onReceive(): device "
+ + device
+ + ", UUID="
+ + Arrays.toString(uuids));
+ }
}
return null;
})
diff --git a/framework/tests/unit/Android.bp b/framework/tests/unit/Android.bp
index 39b3c29861..df2dc8b9dc 100644
--- a/framework/tests/unit/Android.bp
+++ b/framework/tests/unit/Android.bp
@@ -34,5 +34,6 @@ android_test {
test_suites: [
"general-tests",
"mts-bluetooth",
+ "mts-bt",
],
}
diff --git a/framework/tests/unit/src/android/bluetooth/BluetoothDeviceTest.java b/framework/tests/unit/src/android/bluetooth/BluetoothDeviceTest.java
new file mode 100644
index 0000000000..55263c4400
--- /dev/null
+++ b/framework/tests/unit/src/android/bluetooth/BluetoothDeviceTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothDevice.AddressType;
+import android.bluetooth.BluetoothDevice.BluetoothAddress;
+import android.os.Parcel;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test cases for {@link BluetoothDevice}. */
+@RunWith(JUnit4.class)
+public class BluetoothDeviceTest {
+
+ @Test
+ public void testBluetoothAddress_empty() {
+ BluetoothAddress bluetoothAddress =
+ new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN);
+
+ assertThat(bluetoothAddress.getAddress()).isNull();
+ assertThat(bluetoothAddress.getAddressType())
+ .isEqualTo(BluetoothDevice.ADDRESS_TYPE_UNKNOWN);
+ }
+
+ @Test
+ public void testBluetoothAddress_addressWithTypePublic() {
+ doTestAddressWithType("00:11:22:AA:BB:CC", BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+ }
+
+ @Test
+ public void testBluetoothAddress_addressWithTypeRandom() {
+ doTestAddressWithType("51:F7:A8:75:AC:5E", BluetoothDevice.ADDRESS_TYPE_RANDOM);
+ }
+
+ @Test
+ public void testBluetoothAddress_Parcelable() {
+ String address = "00:11:22:AA:BB:CC";
+ int addressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC;
+
+ BluetoothAddress bluetoothAddress = new BluetoothAddress(address, addressType);
+
+ doAssertBluetoothAddress(bluetoothAddress, address, addressType);
+
+ Parcel parcel = Parcel.obtain();
+ bluetoothAddress.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+ BluetoothAddress bluetoothAddressOut = BluetoothAddress.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ doAssertBluetoothAddress(bluetoothAddressOut, address, addressType);
+ }
+
+ private void doTestAddressWithType(String address, @AddressType int addressType) {
+ BluetoothAddress bluetoothAddress = new BluetoothAddress(address, addressType);
+
+ doAssertBluetoothAddress(bluetoothAddress, address, addressType);
+ }
+
+ private void doAssertBluetoothAddress(
+ BluetoothAddress bluetoothAddress, String address, @AddressType int addressType) {
+ assertThat(bluetoothAddress.getAddress()).isEqualTo(address);
+ assertThat(bluetoothAddress.getAddressType())
+ .isEqualTo(
+ addressType == BluetoothDevice.ADDRESS_TYPE_RANDOM
+ ? BluetoothDevice.ADDRESS_TYPE_RANDOM
+ : BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+ }
+}
diff --git a/framework/tests/util/Android.bp b/framework/tests/util/Android.bp
index f1e942f4c6..dc42f777a5 100644
--- a/framework/tests/util/Android.bp
+++ b/framework/tests/util/Android.bp
@@ -43,6 +43,7 @@ java_library {
"//packages/modules/Connectivity/nearby/tests/cts/fastpair",
"//packages/modules/Permission/tests/cts/permission",
"//packages/modules/Permission/tests/cts/permissionui",
+ "//packages/modules/Uwb/ranging/tests/cts/tests",
"//test/cts-root/tests/bluetooth",
],
}
diff --git a/pandora/interfaces/pandora_experimental/hid.proto b/pandora/interfaces/pandora_experimental/hid.proto
index 709d1577ff..258b72dad0 100644
--- a/pandora/interfaces/pandora_experimental/hid.proto
+++ b/pandora/interfaces/pandora_experimental/hid.proto
@@ -7,6 +7,8 @@ option java_outer_classname = "HidProto";
import "google/protobuf/empty.proto";
service HID {
+ // Register service
+ rpc RegisterService(ServiceRequest) returns (google.protobuf.Empty);
// Connect HID Host
rpc ConnectHost(google.protobuf.Empty) returns (google.protobuf.Empty);
// Disconnect HID Host
@@ -39,6 +41,16 @@ enum HidReportId {
HID_INVALID_RPT_ID = 3;
}
+enum HidServiceType {
+ SERVICE_TYPE_HID = 0;
+ SERVICE_TYPE_HOGP = 1;
+ SERVICE_TYPE_BOTH = 2;
+}
+
+message ServiceRequest {
+ HidServiceType service_type = 1;
+}
+
message SendHostReportRequest {
bytes address = 1;
HidReportType report_type = 2;
diff --git a/pandora/server/bumble_experimental/hid.py b/pandora/server/bumble_experimental/hid.py
index 78491f2547..23b1c76047 100644
--- a/pandora/server/bumble_experimental/hid.py
+++ b/pandora/server/bumble_experimental/hid.py
@@ -18,6 +18,8 @@ from pandora_experimental.hid_pb2 import (
PROTOCOL_REPORT_MODE,
PROTOCOL_BOOT_MODE,
PROTOCOL_UNSUPPORTED_MODE,
+ SERVICE_TYPE_HID,
+ SERVICE_TYPE_HOGP,
)
from bumble.core import (
@@ -705,6 +707,21 @@ def on_virtual_cable_unplug_cb():
hid_protoMode_queue = None
hid_report_queue = None
+hid_device = None
+
+
+def register_hid(self) -> None:
+ self.device.sdp_service_records.update(sdp_records())
+ global hid_device
+ hid_device = HID_Device(self.device)
+ # Register for call backs
+ hid_device.register_get_report_cb(on_get_report_cb)
+ hid_device.register_set_report_cb(on_set_report_cb)
+ hid_device.register_get_protocol_cb(on_get_protocol_cb)
+ hid_device.register_set_protocol_cb(on_set_protocol_cb)
+ # Register for virtual cable unplug call back
+ hid_device.on('virtual_cable_unplug', on_virtual_cable_unplug_cb)
+
# This class implements the Hid Pandora interface.
class HIDService(HIDServicer):
@@ -714,19 +731,23 @@ class HIDService(HIDServicer):
def __init__(self, device: Device) -> None:
super().__init__()
self.device = device
- self.device.sdp_service_records.update(sdp_records())
self.event_queue: Optional[asyncio.Queue[ProtocolModeEvent]] = None
- hogp_device(self.device)
- logging.info(f'Hid device register: ')
- global hid_device
- hid_device = HID_Device(self.device)
- # Register for call backs
- hid_device.register_get_report_cb(on_get_report_cb)
- hid_device.register_set_report_cb(on_set_report_cb)
- hid_device.register_get_protocol_cb(on_get_protocol_cb)
- hid_device.register_set_protocol_cb(on_set_protocol_cb)
- # Register for virtual cable unplug call back
- hid_device.on('virtual_cable_unplug', on_virtual_cable_unplug_cb)
+
+ @utils.rpc
+ async def RegisterService(self, request: empty_pb2.Empty, context: grpc.ServicerContext) -> empty_pb2.Empty:
+
+ if request.service_type == SERVICE_TYPE_HID:
+ logging.info(f'Registering HID')
+ register_hid(self)
+ elif request.service_type == SERVICE_TYPE_HOGP:
+ logging.info(f'Registering HOGP')
+ hogp_device(self.device)
+ else:
+ logging.info(f'Registering both HID and HOGP')
+ register_hid(self)
+ hogp_device(self.device)
+
+ return empty_pb2.Empty()
@utils.rpc
async def ConnectHost(self, request: empty_pb2.Empty, context: grpc.ServicerContext) -> empty_pb2.Empty:
diff --git a/service/Android.bp b/service/Android.bp
index ccb7f7d63b..5fbf29b91c 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -93,6 +93,7 @@ java_library {
}
// Apply jarjaring before using library in the apex
+// TODO b/383863941 delete and merge with service-bluetooth-new
java_library {
name: "service-bluetooth",
static_libs: ["service-bluetooth-pre-jarjar"],
@@ -116,6 +117,30 @@ java_library {
visibility: ["//packages/modules/Bluetooth/apex"],
}
+// Apply jarjaring before using library in the apex
+java_library {
+ name: "service-bluetooth-new",
+ static_libs: ["service-bluetooth-pre-jarjar"],
+ installable: true,
+
+ jarjar_rules: ":bluetooth-jarjar-rules",
+
+ optimize: {
+ enabled: true,
+ shrink: true,
+ proguard_flags_files: ["proguard.flags"],
+ },
+
+ libs: [
+ "framework-bluetooth.impl",
+ ],
+
+ sdk_version: "system_server_current",
+ min_sdk_version: "Tiramisu",
+ apex_available: ["com.android.bt"],
+ visibility: ["//packages/modules/Bluetooth/apex"],
+}
+
java_library {
name: "bluetooth-manager-service-proto-java-gen",
srcs: [":srcs_bluetooth_manager_service_proto"],
diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
index a78d85797d..0cfdfea987 100644
--- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java
+++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
@@ -62,7 +62,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.database.ContentObserver;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -79,7 +78,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import android.sysprop.BluetoothProperties;
import android.util.proto.ProtoOutputStream;
@@ -589,11 +587,7 @@ class BluetoothManagerService {
mHandler = new BluetoothHandler(mLooper);
// Observe BLE scan only mode settings change.
- if (Flags.respectBleScanSetting()) {
- BleScanSettingListener.initialize(mLooper, mContentResolver, this::onBleScanDisabled);
- } else {
- registerForBleScanModeChange();
- }
+ BleScanSettingListener.initialize(mLooper, mContentResolver, this::onBleScanDisabled);
// Disable ASHA if BLE is not supported, overriding any system property
if (!isBleSupported(mContext)) {
@@ -684,13 +678,6 @@ class BluetoothManagerService {
}
clearBleApps();
- if (!Flags.bleScanSettingDoesNotDisconnectIfBtOn()) {
- try {
- mAdapter.unregAllGattClient(mContext.getAttributionSource());
- } catch (RemoteException e) {
- Log.e(TAG, "onBleScanDisabled: unregAllGattClient failed", e);
- }
- }
if (mState.oneOf(STATE_BLE_ON)) {
Log.i(TAG, "onBleScanDisabled: Shutting down BLE_ON mode");
bleOnToOff();
@@ -868,20 +855,10 @@ class BluetoothManagerService {
if (AirplaneModeListener.isOn() && !mEnable) {
return false;
}
- if (Flags.respectBleScanSetting()) {
- if (SatelliteModeListener.isOn()) {
- return false;
- }
- return BleScanSettingListener.isScanAllowed();
- }
- try {
- return Settings.Global.getInt(
- mContentResolver, BleScanSettingListener.BLE_SCAN_ALWAYS_AVAILABLE)
- != 0;
- } catch (SettingNotFoundException e) {
- // The settings is considered as false by default.
+ if (SatelliteModeListener.isOn()) {
return false;
}
+ return BleScanSettingListener.isScanAllowed();
}
boolean isHearingAidProfileSupported() {
@@ -899,32 +876,6 @@ class BluetoothManagerService {
return mAdapter.isMediaProfileConnected(mContext.getAttributionSource());
}
- // Monitor change of BLE scan only mode settings.
- private void registerForBleScanModeChange() {
- ContentObserver contentObserver =
- new ContentObserver(new Handler(mLooper)) {
- @Override
- public void onChange(boolean selfChange) {
- if (isBleScanAvailable()) {
- // Nothing to do
- return;
- }
- // BLE scan is not available.
- disableBleScanMode();
- clearBleApps();
- if (mState.oneOf(STATE_BLE_ON)) {
- ActiveLogs.add(ENABLE_DISABLE_REASON_APPLICATION_REQUEST, false);
- bleOnToOff();
- }
- }
- };
-
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(BleScanSettingListener.BLE_SCAN_ALWAYS_AVAILABLE),
- false,
- contentObserver);
- }
-
// Disable ble scan only mode.
private void disableBleScanMode() {
if (mState.oneOf(STATE_ON)) {
@@ -979,7 +930,7 @@ class BluetoothManagerService {
return false;
}
- if (Flags.respectBleScanSetting() && !BleScanSettingListener.isScanAllowed()) {
+ if (!BleScanSettingListener.isScanAllowed()) {
Log.d(TAG, "enableBle: not enabling - Scan mode is not allowed.");
return false;
}
@@ -1012,12 +963,6 @@ class BluetoothManagerService {
+ (" isBinding=" + isBinding())
+ (" mState=" + mState));
- // Remove this with flag, preventing a "disable" make no sense, even in satellite mode
- if (!Flags.respectBleScanSetting() && isSatelliteModeOn()) {
- Log.d(TAG, "disableBle: not disabling - satellite mode is on.");
- return false;
- }
-
if (mState.oneOf(STATE_OFF)) {
Log.i(TAG, "disableBle: Already disabled");
return false;
@@ -1082,9 +1027,9 @@ class BluetoothManagerService {
Log.d(TAG, "sendBrEdrDownCallback: mAdapter is null");
return;
}
- boolean scanIsAllowed =
- !Flags.respectBleScanSetting() || BleScanSettingListener.isScanAllowed();
- if (!AirplaneModeListener.isOn() && isBleAppPresent() && scanIsAllowed) {
+ if (BleScanSettingListener.isScanAllowed()
+ && !AirplaneModeListener.isOn()
+ && isBleAppPresent()) {
// Need to stay at BLE ON. Disconnect all Gatt connections
Log.i(TAG, "sendBrEdrDownCallback: Staying in BLE_ON");
try {
diff --git a/service/tests/Android.bp b/service/tests/Android.bp
index e3b70c81d0..217bd36f70 100644
--- a/service/tests/Android.bp
+++ b/service/tests/Android.bp
@@ -58,6 +58,7 @@ android_test {
test_suites: [
"general-tests",
"mts-bluetooth",
+ "mts-bt",
],
min_sdk_version: "Tiramisu",
diff --git a/system/Android.bp b/system/Android.bp
index b79fa12489..1ecb8b81d7 100644
--- a/system/Android.bp
+++ b/system/Android.bp
@@ -11,140 +11,12 @@ package {
}
filegroup {
- name: "BlueberryFacadeProto",
- srcs: [
- "blueberry/facade/common.proto",
- "blueberry/facade/hal/hal_facade.proto",
- "blueberry/facade/hci/acl_manager_facade.proto",
- "blueberry/facade/hci/controller_facade.proto",
- "blueberry/facade/hci/hci_facade.proto",
- "blueberry/facade/hci/le_acl_manager_facade.proto",
- "blueberry/facade/hci/le_advertising_manager_facade.proto",
- "blueberry/facade/hci/le_initiator_address_facade.proto",
- "blueberry/facade/hci/le_scanning_manager_facade.proto",
- "blueberry/facade/l2cap/classic/facade.proto",
- "blueberry/facade/l2cap/le/facade.proto",
- "blueberry/facade/neighbor/facade.proto",
- "blueberry/facade/rootservice.proto",
- "blueberry/facade/topshim/facade.proto",
- ],
-}
-
-filegroup {
name: "TestMockCodecManager",
srcs: [
"bta/le_audio/mock_codec_manager.cc",
],
}
-genrule {
- name: "BlueberryFacadeGeneratedStub_h",
- tools: [
- "aprotoc",
- "protoc-gen-grpc-cpp-plugin",
- ],
- cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(locations :BlueberryFacadeProto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
- srcs: [
- ":BlueberryFacadeProto",
- ":libprotobuf-internal-protos",
- ],
- out: [
- "blueberry/facade/common.grpc.pb.h",
- "blueberry/facade/common.pb.h",
- "blueberry/facade/hal/hal_facade.grpc.pb.h",
- "blueberry/facade/hal/hal_facade.pb.h",
- "blueberry/facade/hci/acl_manager_facade.grpc.pb.h",
- "blueberry/facade/hci/acl_manager_facade.pb.h",
- "blueberry/facade/hci/controller_facade.grpc.pb.h",
- "blueberry/facade/hci/controller_facade.pb.h",
- "blueberry/facade/hci/hci_facade.grpc.pb.h",
- "blueberry/facade/hci/hci_facade.pb.h",
- "blueberry/facade/hci/le_acl_manager_facade.grpc.pb.h",
- "blueberry/facade/hci/le_acl_manager_facade.pb.h",
- "blueberry/facade/hci/le_advertising_manager_facade.grpc.pb.h",
- "blueberry/facade/hci/le_advertising_manager_facade.pb.h",
- "blueberry/facade/hci/le_initiator_address_facade.grpc.pb.h",
- "blueberry/facade/hci/le_initiator_address_facade.pb.h",
- "blueberry/facade/hci/le_scanning_manager_facade.grpc.pb.h",
- "blueberry/facade/hci/le_scanning_manager_facade.pb.h",
- "blueberry/facade/l2cap/classic/facade.grpc.pb.h",
- "blueberry/facade/l2cap/classic/facade.pb.h",
- "blueberry/facade/l2cap/le/facade.grpc.pb.h",
- "blueberry/facade/l2cap/le/facade.pb.h",
- "blueberry/facade/neighbor/facade.grpc.pb.h",
- "blueberry/facade/neighbor/facade.pb.h",
- "blueberry/facade/rootservice.grpc.pb.h",
- "blueberry/facade/rootservice.pb.h",
- ],
-}
-
-genrule {
- name: "BlueberryFacadeGeneratedStub_cc",
- tools: [
- "aprotoc",
- "protoc-gen-grpc-cpp-plugin",
- ],
- cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(locations :BlueberryFacadeProto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
- srcs: [
- ":BlueberryFacadeProto",
- ":libprotobuf-internal-protos",
- ],
- out: [
- "blueberry/facade/common.grpc.pb.cc",
- "blueberry/facade/common.pb.cc",
- "blueberry/facade/hal/hal_facade.grpc.pb.cc",
- "blueberry/facade/hal/hal_facade.pb.cc",
- "blueberry/facade/hci/acl_manager_facade.grpc.pb.cc",
- "blueberry/facade/hci/acl_manager_facade.pb.cc",
- "blueberry/facade/hci/controller_facade.grpc.pb.cc",
- "blueberry/facade/hci/controller_facade.pb.cc",
- "blueberry/facade/hci/hci_facade.grpc.pb.cc",
- "blueberry/facade/hci/hci_facade.pb.cc",
- "blueberry/facade/hci/le_acl_manager_facade.grpc.pb.cc",
- "blueberry/facade/hci/le_acl_manager_facade.pb.cc",
- "blueberry/facade/hci/le_advertising_manager_facade.grpc.pb.cc",
- "blueberry/facade/hci/le_advertising_manager_facade.pb.cc",
- "blueberry/facade/hci/le_initiator_address_facade.grpc.pb.cc",
- "blueberry/facade/hci/le_initiator_address_facade.pb.cc",
- "blueberry/facade/hci/le_scanning_manager_facade.grpc.pb.cc",
- "blueberry/facade/hci/le_scanning_manager_facade.pb.cc",
- "blueberry/facade/l2cap/classic/facade.grpc.pb.cc",
- "blueberry/facade/l2cap/classic/facade.pb.cc",
- "blueberry/facade/l2cap/le/facade.grpc.pb.cc",
- "blueberry/facade/l2cap/le/facade.pb.cc",
- "blueberry/facade/neighbor/facade.grpc.pb.cc",
- "blueberry/facade/neighbor/facade.pb.cc",
- "blueberry/facade/rootservice.grpc.pb.cc",
- "blueberry/facade/rootservice.pb.cc",
- ],
-}
-
-genrule {
- name: "BlueberryFacadeAndCertGeneratedStub_py",
- tools: [
- "aprotoc",
- "protoc-gen-grpc-python-plugin",
- "soong_zip",
- ],
- cmd: "mkdir -p $(genDir)/files && " +
- "$(location aprotoc) -Ipackages/modules/Bluetooth/system -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(locations :BlueberryFacadeProto) --grpc_out=$(genDir)/files --python_out=$(genDir)/files && " +
- "for dir in `find $(genDir)/files -type d`; do touch $$dir/__init__.py; done &&" +
- "$(location soong_zip) -C $(genDir)/files -D $(genDir)/files -o $(out)",
- srcs: [
- ":BlueberryFacadeProto",
- ":libprotobuf-internal-protos",
- ],
- out: ["blueberry_facade_generated_py.zip"],
-}
-
-rust_protobuf {
- name: "libbt_topshim_facade_protobuf",
- crate_name: "bt_topshim_facade_protobuf",
- source_stem: "topshim_facade",
- host_supported: true,
- grpc_protos: ["blueberry/facade/topshim/facade.proto"],
-}
-
// Export system headers for rules that can't simply use `include_dirs`
cc_library_headers {
name: "libbluetooth_system_headers",
@@ -160,168 +32,3 @@ cc_library_headers {
],
min_sdk_version: "30",
}
-
-genrule {
- name: "bluetooth_cert_test_sources-zip",
- tools: [
- "soong_zip",
- ],
- srcs: [
- "blueberry/**/*.py",
- "blueberry/**/*.yaml",
- "setup.py",
- ],
- out: ["bluetooth_cert_test_sources.zip"],
- cmd: "echo $(in) > $(genDir)/file_list.txt && " +
- "$(location soong_zip) -C packages/modules/Bluetooth/system -l $(genDir)/file_list.txt -o $(out)",
-}
-
-genrule {
- name: "gd_hci_packets_python3_gen-zip",
- tools: [
- "soong_zip",
- ],
- srcs: [
- ":gd_hci_packets_python3_gen",
- ],
- out: ["gd_hci_packets_python3_gen.zip"],
- cmd: "echo $(in) > $(genDir)/file_list.txt && " +
- "$(location soong_zip) -j -l $(genDir)/file_list.txt -o $(out)",
-}
-
-genrule {
- name: "gd_smp_packets_python3_gen-zip",
- tools: [
- "soong_zip",
- ],
- srcs: [
- ":gd_smp_packets_python3_gen",
- ],
- out: ["gd_smp_packets_python3_gen.zip"],
- cmd: "echo $(in) > $(genDir)/file_list.txt && " +
- "$(location soong_zip) -j -l $(genDir)/file_list.txt -o $(out)",
-}
-
-cc_genrule {
- name: "bluetooth_cert_test_host_deps-zip",
- host_supported: true,
- device_supported: false,
- compile_multilib: "first",
- tools: [
- "bluetooth_stack_with_facade",
- "bt_topshim_facade",
- "root-canal",
- "soong_zip",
- ],
- srcs: [
- ":libbase",
- ":libbinder",
- ":libbinder_ndk",
- ":libbluetooth",
- ":libbluetooth_gd",
- ":libc++",
- ":libchrome",
- ":libcrypto",
- ":libcutils",
- ":libevent",
- ":libflatbuffers-cpp",
- ":libgrpc++",
- ":libgrpc_wrap",
- ":liblog",
- ":liblzma",
- ":libprotobuf-cpp-full",
- ":libssl",
- ":libunwindstack",
- ":libutils",
- ":libz",
- ":server_configurable_flags",
- ],
- out: ["bluetooth_cert_test_host_deps.zip"],
- cmd: "echo $(in) > $(genDir)/file_list.txt && " +
- "$(location soong_zip) -j -f $(location bluetooth_stack_with_facade) -f $(location bt_topshim_facade) -f $(location root-canal) -P lib64 -l $(genDir)/file_list.txt -o $(out)",
-}
-
-cc_genrule {
- name: "bluetooth_cert_test_target_deps-zip",
- compile_multilib: "first",
- tools: [
- "soong_zip",
- ],
- srcs: [
- // executables
- ":bluetooth_stack_with_facade",
- // libs
- ":android.hardware.bluetooth@1.0",
- ":android.hardware.bluetooth@1.1",
- ":libandroid_runtime_lazy",
- ":libbase",
- ":libbinder",
- ":libbinder_ndk",
- ":libc++",
- ":libcrypto",
- ":libcutils",
- ":libgrpc++",
- ":libgrpc_wrap",
- ":libhidlbase",
- ":liblog",
- ":liblzma",
- ":libprotobuf-cpp-full",
- ":libssl",
- ":libunwindstack",
- ":libutils",
- ":libz",
- ":server_configurable_flags",
- ],
- out: ["bluetooth_cert_test_target_deps.zip"],
- cmd: "echo $(in) > $(genDir)/file_list.txt && " +
- "$(location soong_zip) -j -P target -l $(genDir)/file_list.txt -o $(out)",
-}
-
-genrule {
- name: "llvm-tools-zip",
- tools: [
- "soong_zip",
- ],
- srcs: [
- ":llvm-tools",
- ],
- out: ["llvm-tools.zip"],
- cmd: "mkdir -p $(genDir)/llvm_binutils/bin && mkdir -p $(genDir)/llvm_binutils/lib/x86_64-unknown-linux-gnu && " +
- "cp prebuilts/clang/host/linux-x86/*/bin/llvm-cov $(genDir)/llvm_binutils/bin && " +
- "cp prebuilts/clang/host/linux-x86/*/bin/llvm-profdata $(genDir)/llvm_binutils/bin && " +
- "cp prebuilts/clang/host/linux-x86/*/bin/llvm-symbolizer $(genDir)/llvm_binutils/bin && " +
- "cp prebuilts/clang/host/linux-x86/*/lib/x86_64-unknown-linux-gnu/libc++.so $(genDir)/llvm_binutils/lib/x86_64-unknown-linux-gnu && " +
- "$(location soong_zip) -C $(genDir) -D $(genDir)/llvm_binutils -o $(out)",
-}
-
-cc_genrule {
- name: "bluetooth_cert_tests.zip",
- host_supported: true,
- device_supported: false,
- compile_multilib: "first",
- tools: [
- "merge_zips",
- "soong_zip",
- ],
- srcs: [
- ":BlueberryFacadeAndCertGeneratedStub_py",
- ":bluetooth_cert_test_host_deps-zip",
- ":bluetooth_cert_test_sources-zip",
- ":gd_hci_packets_python3_gen-zip",
- ":gd_smp_packets_python3_gen-zip",
- ":llvm-tools-zip",
- ],
- device_first_srcs: [
- ":bluetooth_cert_test_target_deps-zip",
- ],
- out: ["bluetooth_cert_tests.zip"],
- cmd: "$(location merge_zips) $(genDir)/temp.zip $(in) && " +
- "unzip -q -d $(genDir)/files $(genDir)/temp.zip && " +
- "for d in $$(find $(genDir)/files/blueberry -type d -name '*'); do touch -a $$d/__init__.py; done && " +
- "$(location soong_zip) -C $(genDir)/files -D $(genDir)/files -o $(out)",
- dist: {
- targets: [
- "bluetooth_stack_with_facade",
- ],
- },
-}
diff --git a/system/BUILD.gn b/system/BUILD.gn
index 783428604a..01286ec4e8 100644
--- a/system/BUILD.gn
+++ b/system/BUILD.gn
@@ -55,7 +55,6 @@ group("bluetooth") {
group("tools") {
deps = [
- "//bt/system/gd/dumpsys/bundler:bluetooth_flatbuffer_bundler",
"//bt/system/gd/packet/parser:bluetooth_packetgen",
]
}
diff --git a/system/OWNERS b/system/OWNERS
index 15ec13fb04..d60842e9c9 100644
--- a/system/OWNERS
+++ b/system/OWNERS
@@ -10,4 +10,3 @@ poahlo@google.com
rongxuan@google.com
rwt@google.com
wescande@google.com
-yuyangh@google.com
diff --git a/system/audio/Android.bp b/system/audio/Android.bp
index d5dde594e1..481182dc5f 100644
--- a/system/audio/Android.bp
+++ b/system/audio/Android.bp
@@ -83,9 +83,6 @@ cc_library_host_shared {
"liblog",
],
stl: "libc++_static",
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
}
python_test_host {
diff --git a/system/audio/asrc/asrc_resampler.cc b/system/audio/asrc/asrc_resampler.cc
index 81d46f1121..7e44d9ade6 100644
--- a/system/audio/asrc/asrc_resampler.cc
+++ b/system/audio/asrc/asrc_resampler.cc
@@ -16,7 +16,6 @@
#include "asrc_resampler.h"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
diff --git a/system/audio_bluetooth_hw/Android.bp b/system/audio_bluetooth_hw/Android.bp
index fe53c511a2..030fef1942 100644
--- a/system/audio_bluetooth_hw/Android.bp
+++ b/system/audio_bluetooth_hw/Android.bp
@@ -51,7 +51,7 @@ cc_library_shared {
"libhidlbase",
],
visibility: [
- "//device/generic/goldfish/audio",
+ "//device/generic/goldfish/hals/audio",
],
}
diff --git a/system/audio_hal_interface/Android.bp b/system/audio_hal_interface/Android.bp
index f485de80aa..363627401f 100644
--- a/system/audio_hal_interface/Android.bp
+++ b/system/audio_hal_interface/Android.bp
@@ -228,7 +228,6 @@ cc_defaults {
"android.hardware.common.fmq-V1-ndk",
"libFraunhoferAAC",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-protos",
"libbluetooth-types",
"libbluetooth_core_rs",
@@ -292,6 +291,7 @@ cc_test {
"aidl/le_audio_utils_unittest.cc",
],
shared_libs: [
+ "libaconfig_storage_read_api_cc",
"libbase",
"libbinder",
"libbinder_ndk",
diff --git a/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc b/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc
index 6b8a2b4195..cfb0d020d4 100644
--- a/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc
+++ b/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc
@@ -306,10 +306,7 @@ static bool a2dp_get_selected_hal_pcm_config(A2dpCodecConfig* a2dp_codec_configs
pcm_config->sampleRateHz = A2dpCodecToHalSampleRate(current_codec);
pcm_config->bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec);
pcm_config->channelMode = A2dpCodecToHalChannelMode(current_codec);
-
- if (com::android::bluetooth::flags::a2dp_aidl_encoding_interval()) {
- pcm_config->dataIntervalUs = preferred_encoding_interval_us;
- }
+ pcm_config->dataIntervalUs = preferred_encoding_interval_us;
return pcm_config->sampleRateHz > 0 && pcm_config->bitsPerSample > 0 &&
pcm_config->channelMode != ChannelMode::UNKNOWN;
diff --git a/system/audio_hal_interface/fuzzer/Android.bp b/system/audio_hal_interface/fuzzer/Android.bp
index 9a32f910e3..f2301b6d00 100644
--- a/system/audio_hal_interface/fuzzer/Android.bp
+++ b/system/audio_hal_interface/fuzzer/Android.bp
@@ -59,7 +59,6 @@ cc_defaults {
"bluetooth_flags_c_lib",
"libFraunhoferAAC",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-protos",
"libbluetooth-types",
"libbluetooth_core_rs",
diff --git a/system/blueberry/facade/common.proto b/system/blueberry/facade/common.proto
deleted file mode 100644
index 42c6aaa3f7..0000000000
--- a/system/blueberry/facade/common.proto
+++ /dev/null
@@ -1,35 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade;
-
-message Data {
- bytes payload = 1;
-}
-
-message BluetoothAddress {
- bytes address = 1;
-}
-
-enum BluetoothAddressTypeEnum {
- PUBLIC_DEVICE_ADDRESS = 0x0;
- RANDOM_DEVICE_ADDRESS = 0x1;
- PUBLIC_IDENTITY_ADDRESS = 0x2;
- RANDOM_IDENTITY_ADDRESS = 0x3;
-}
-
-enum BluetoothOwnAddressTypeEnum {
- USE_PUBLIC_DEVICE_ADDRESS = 0x0;
- USE_RANDOM_DEVICE_ADDRESS = 0x1;
- RESOLVABLE_OR_PUBLIC_ADDRESS = 0x2;
- RESOLVABLE_OR_RANDOM_ADDRESS = 0x3;
-}
-
-message BluetoothAddressWithType {
- BluetoothAddress address = 1;
- BluetoothAddressTypeEnum type = 2;
-}
-
-enum BluetoothPeerAddressTypeEnum {
- PUBLIC_DEVICE_OR_IDENTITY_ADDRESS = 0x0;
- RANDOM_DEVICE_OR_IDENTITY_ADDRESS = 0x1;
-}
diff --git a/system/blueberry/facade/hal/hal_facade.proto b/system/blueberry/facade/hal/hal_facade.proto
deleted file mode 100644
index d09d0e4923..0000000000
--- a/system/blueberry/facade/hal/hal_facade.proto
+++ /dev/null
@@ -1,20 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hal;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service HciHalFacade {
- rpc SendCommand(blueberry.facade.Data) returns (google.protobuf.Empty) {}
- rpc StreamEvents(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-
- rpc SendAcl(blueberry.facade.Data) returns (google.protobuf.Empty) {}
- rpc StreamAcl(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-
- rpc SendSco(blueberry.facade.Data) returns (google.protobuf.Empty) {}
- rpc StreamSco(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-
- rpc SendIso(blueberry.facade.Data) returns (google.protobuf.Empty) {}
- rpc StreamIso(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-}
diff --git a/system/blueberry/facade/hci/acl_manager_facade.proto b/system/blueberry/facade/hci/acl_manager_facade.proto
deleted file mode 100644
index 69f408a34d..0000000000
--- a/system/blueberry/facade/hci/acl_manager_facade.proto
+++ /dev/null
@@ -1,53 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-
-service AclManagerFacade {
- rpc CreateConnection(ConnectionMsg) returns (stream ConnectionEvent) {}
- rpc CancelConnection(ConnectionMsg) returns (google.protobuf.Empty) {}
- rpc Disconnect(HandleMsg) returns (google.protobuf.Empty) {}
- rpc WriteDefaultLinkPolicySettings(PolicyMsg) returns (google.protobuf.Empty) {}
- rpc AuthenticationRequested(HandleMsg) returns (google.protobuf.Empty) {}
- rpc ConnectionCommand(ConnectionCommandMsg) returns (google.protobuf.Empty) {}
- rpc SwitchRole(RoleMsg) returns (google.protobuf.Empty) {}
- rpc SendAclData(AclData) returns (google.protobuf.Empty) {}
- rpc FetchAclData(HandleMsg) returns (stream AclData) {}
- rpc FetchIncomingConnection(google.protobuf.Empty) returns (stream ConnectionEvent) {}
-}
-
-message HandleMsg {
- uint32 handle = 1;
-}
-
-message ConnectionMsg {
- bytes address = 1;
-}
-
-message PolicyMsg {
- uint32 policy = 1;
-}
-
-enum NewRole {
- CENTRAL = 0;
- PERIPHERAL = 1;
-}
-
-message RoleMsg {
- bytes address = 1;
- NewRole role = 2;
-}
-
-message ConnectionCommandMsg {
- bytes packet = 1;
-}
-
-message ConnectionEvent {
- bytes payload = 1;
-}
-
-message AclData {
- uint32 handle = 1;
- bytes payload = 2;
-}
diff --git a/system/blueberry/facade/hci/controller_facade.proto b/system/blueberry/facade/hci/controller_facade.proto
deleted file mode 100644
index 7eb46a6abb..0000000000
--- a/system/blueberry/facade/hci/controller_facade.proto
+++ /dev/null
@@ -1,96 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service ControllerFacade {
- rpc GetMacAddress(google.protobuf.Empty) returns (blueberry.facade.BluetoothAddress) {}
- rpc WriteLocalName(NameMsg) returns (google.protobuf.Empty) {}
- rpc GetLocalName(google.protobuf.Empty) returns (NameMsg) {}
- rpc IsSupportedCommand(OpCodeMsg) returns (SupportedMsg) {}
- rpc GetLeNumberOfSupportedAdvertisingSets(google.protobuf.Empty) returns (SingleValueMsg) {}
- rpc SupportsSimplePairing(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsSecureConnections(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsSimultaneousLeBrEdr(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsInterlacedInquiryScan(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsRssiWithInquiryResults(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsExtendedInquiryResponse(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsRoleSwitch(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc Supports3SlotPackets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc Supports5SlotPackets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsClassic2mPhy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsClassic3mPhy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc Supports3SlotEdrPackets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc Supports5SlotEdrPackets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsSco(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsHv2Packets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsHv3Packets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsEv3Packets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsEv4Packets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsEv5Packets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsEsco2mPhy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsEsco3mPhy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc Supports3SlotEscoEdrPackets(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsHoldMode(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsSniffMode(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsParkMode(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsNonFlushablePb(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsSniffSubrating(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsEncryptionPause(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBle(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleEncryption(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectionParametersRequest(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleExtendedReject(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePeripheralInitiatedFeaturesExchange(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePing(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleDataPacketLengthExtension(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePrivacy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleExtendedScannerFilterPolicies(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBle2mPhy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleStableModulationIndexTx(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleStableModulationIndexRx(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleCodedPhy(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleExtendedAdvertising(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePeriodicAdvertising(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleChannelSelectionAlgorithm2(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePowerClass1(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleMinimumUsedChannels(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectionCteRequest(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectionCteResponse(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectionlessCteTransmitter(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectionlessCteReceiver(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleAntennaSwitchingDuringCteTx(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleAntennaSwitchingDuringCteRx(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleReceivingConstantToneExtensions(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePeriodicAdvertisingSyncTransferSender(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePeriodicAdvertisingSyncTransferRecipient(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleSleepClockAccuracyUpdates(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleRemotePublicKeyValidation(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectedIsochronousStreamCentral(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleConnectedIsochronousStreamPeripheral(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleIsochronousBroadcaster(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleSynchronizedReceiver(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBleIsochronousChannelsHostSupport(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePowerControlRequest(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePowerChangeIndication(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePathLossMonitoring(google.protobuf.Empty) returns (SupportedMsg) {}
- rpc SupportsBlePeriodicAdvertisingAdi(google.protobuf.Empty) returns (SupportedMsg) {}
-}
-
-message NameMsg {
- bytes name = 1;
-}
-
-message OpCodeMsg {
- uint32 op_code = 1;
-}
-
-message SupportedMsg {
- bool supported = 1;
-}
-
-message SingleValueMsg {
- uint64 value = 1;
-} \ No newline at end of file
diff --git a/system/blueberry/facade/hci/hci_facade.proto b/system/blueberry/facade/hci/hci_facade.proto
deleted file mode 100644
index 253708ce2f..0000000000
--- a/system/blueberry/facade/hci/hci_facade.proto
+++ /dev/null
@@ -1,23 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service HciFacade {
- rpc SendCommand(blueberry.facade.Data) returns (google.protobuf.Empty) {}
-
- rpc RequestEvent(EventRequest) returns (google.protobuf.Empty) {}
- rpc StreamEvents(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-
- rpc RequestLeSubevent(EventRequest) returns (google.protobuf.Empty) {}
- rpc StreamLeSubevents(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-
- rpc SendAcl(blueberry.facade.Data) returns (google.protobuf.Empty) {}
- rpc StreamAcl(google.protobuf.Empty) returns (stream blueberry.facade.Data) {}
-}
-
-message EventRequest {
- uint32 code = 1;
-}
diff --git a/system/blueberry/facade/hci/le_acl_manager_facade.proto b/system/blueberry/facade/hci/le_acl_manager_facade.proto
deleted file mode 100644
index ad6423fb36..0000000000
--- a/system/blueberry/facade/hci/le_acl_manager_facade.proto
+++ /dev/null
@@ -1,56 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service LeAclManagerFacade {
- rpc CreateConnection(CreateConnectionMsg) returns (stream LeConnectionEvent) {}
- rpc CancelConnection(blueberry.facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {}
- rpc Disconnect(LeHandleMsg) returns (google.protobuf.Empty) {}
- rpc ConnectionCommand(LeConnectionCommandMsg) returns (google.protobuf.Empty) {}
- rpc SendAclData(LeAclData) returns (google.protobuf.Empty) {}
- rpc FetchAclData(LeHandleMsg) returns (stream LeAclData) {}
- rpc FetchIncomingConnection(google.protobuf.Empty) returns (stream LeConnectionEvent) {}
- rpc AddDeviceToResolvingList(IrkMsg) returns (google.protobuf.Empty) {}
- rpc IsOnBackgroundList(BackgroundRequestMsg) returns (BackgroundResultMsg) {}
- rpc RemoveFromBackgroundList(BackgroundRequestMsg)
- returns (google.protobuf.Empty) {}
-}
-
-message LeHandleMsg {
- uint32 handle = 1;
-}
-
-message LeConnectionEvent {
- bytes payload = 1;
-}
-
-message LeConnectionCommandMsg {
- bytes packet = 1;
-}
-
-message LeAclData {
- uint32 handle = 1;
- bytes payload = 2;
-}
-
-message CreateConnectionMsg {
- blueberry.facade.BluetoothAddressWithType peer_address = 1;
- bool is_direct = 2;
-}
-
-message IrkMsg {
- blueberry.facade.BluetoothAddressWithType peer = 1;
- bytes peer_irk = 2;
- bytes local_irk = 3;
-}
-
-message BackgroundRequestMsg {
- blueberry.facade.BluetoothAddressWithType peer_address = 1;
-}
-
-message BackgroundResultMsg {
- bool is_on_background_list = 1;
-}
diff --git a/system/blueberry/facade/hci/le_advertising_manager_facade.proto b/system/blueberry/facade/hci/le_advertising_manager_facade.proto
deleted file mode 100644
index bec06edf86..0000000000
--- a/system/blueberry/facade/hci/le_advertising_manager_facade.proto
+++ /dev/null
@@ -1,180 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service LeAdvertisingManagerFacade {
- rpc CreateAdvertiser(CreateAdvertiserRequest) returns (CreateAdvertiserResponse) {}
- rpc ExtendedCreateAdvertiser(ExtendedCreateAdvertiserRequest) returns (ExtendedCreateAdvertiserResponse) {}
- rpc EnableAdvertiser(EnableAdvertiserRequest) returns (google.protobuf.Empty) {}
- rpc SetData(SetDataRequest) returns (google.protobuf.Empty) {}
- rpc SetParameters(SetParametersRequest) returns (google.protobuf.Empty) {}
- rpc SetPeriodicParameters(SetPeriodicParametersRequest) returns (google.protobuf.Empty) {}
- rpc SetPeriodicData(SetPeriodicDataRequest) returns (google.protobuf.Empty) {}
- rpc EnablePeriodicAdvertising(EnablePeriodicAdvertisingRequest) returns (google.protobuf.Empty) {}
- rpc GetOwnAddress(GetOwnAddressRequest) returns (google.protobuf.Empty) {}
- rpc GetNumberOfAdvertisingInstances(google.protobuf.Empty) returns (GetNumberOfAdvertisingInstancesResponse) {}
- rpc RemoveAdvertiser(RemoveAdvertiserRequest) returns (google.protobuf.Empty) {}
- rpc FetchCallbackEvents(google.protobuf.Empty) returns (stream AdvertisingCallbackMsg) {}
- rpc FetchAddressEvents(google.protobuf.Empty) returns (stream AddressMsg) {}
-}
-
-message GapDataMsg {
- bytes data = 1;
-}
-
-enum AdvertisingEventType {
- ADV_IND = 0x0;
- ADV_DIRECT_IND = 0x1;
- ADV_SCAN_IND = 0x2;
- ADV_NONCONN_IND = 0x3;
- ADV_DIRECT_IND_LOW = 0x4;
-}
-
-enum AdvertisingFilterPolicy {
- ALL_DEVICES = 0x0;
- LISTED_SCAN = 0x1;
- LISTED_CONNECT = 0x2;
- LISTED_SCAN_AND_CONNECT = 0x3;
-};
-
-enum AdvertisingProperty {
- NONE = 0x00;
- INCLUDE_TX_POWER = 0x06;
-};
-
-enum AdvertisingStatus {
- ADV_SUCCESS = 0x00;
- ADV_DATA_TOO_LARGE = 0x01;
- ADV_TOO_MANY_ADVERTISERS = 0x02;
- ADV_ALREADY_STARTED = 0x03;
- ADV_INTERNAL_ERROR = 0x04;
- ADV_FEATURE_UNSUPPORTED = 0x05;
-};
-
-message AdvertisingConfig {
- repeated GapDataMsg advertisement = 1;
- repeated GapDataMsg scan_response = 2;
- // Unit: number of Bluetooth slots in 0.125 ms increment
- int32 interval_min = 4;
- // Unit: number of Bluetooth slots in 0.125 ms increment
- int32 interval_max = 5;
- AdvertisingEventType advertising_type = 6;
- blueberry.facade.BluetoothOwnAddressTypeEnum own_address_type = 7;
- blueberry.facade.BluetoothPeerAddressTypeEnum peer_address_type = 8;
- blueberry.facade.BluetoothAddress peer_address = 9;
- int32 channel_map = 10;
- AdvertisingFilterPolicy filter_policy = 11;
- int32 tx_power = 12;
-}
-
-message ExtendedAdvertisingConfig {
- AdvertisingConfig advertising_config = 1;
- bool connectable = 2;
- bool scannable = 3;
- bool directed = 4;
- bool high_duty_directed_connectable = 5;
- bool legacy_pdus = 6;
- bool anonymous = 7;
- bool include_tx_power = 8;
- bool use_le_coded_phy = 9;
- int32 secondary_max_skip = 10;
- int32 secondary_advertising_phy = 11;
- int32 sid = 12;
- bool enable_scan_request_notifications = 13;
-}
-
-message PeriodicAdvertisingParameters {
- int32 min_interval = 1;
- int32 max_interval = 2;
- AdvertisingProperty advertising_property = 3;
-}
-
-message CreateAdvertiserRequest {
- AdvertisingConfig config = 1;
-}
-
-message CreateAdvertiserResponse {
- // -1 on error
- int32 advertiser_id = 1;
-}
-
-message ExtendedCreateAdvertiserRequest {
- ExtendedAdvertisingConfig config = 1;
-}
-
-message ExtendedCreateAdvertiserResponse {
- // -1 on error
- int32 advertiser_id = 1;
-}
-
-message EnableAdvertiserRequest {
- int32 advertiser_id = 1;
- bool enable = 2;
-}
-
-message SetDataRequest {
- int32 advertiser_id = 1;
- bool set_scan_rsp = 2;
- repeated GapDataMsg data = 3;
-}
-
-message SetParametersRequest {
- int32 advertiser_id = 1;
- AdvertisingConfig config = 2;
-}
-
-message SetPeriodicParametersRequest {
- int32 advertiser_id = 1;
- PeriodicAdvertisingParameters config = 2;
-}
-
-message SetPeriodicDataRequest {
- int32 advertiser_id = 1;
- repeated GapDataMsg data = 2;
-}
-
-message EnablePeriodicAdvertisingRequest {
- int32 advertiser_id = 1;
- bool enable = 2;
- bool include_adi = 3;
-}
-
-message GetOwnAddressRequest {
- int32 advertiser_id = 1;
-}
-
-message GetNumberOfAdvertisingInstancesResponse {
- int32 num_advertising_instances = 1;
-}
-
-message RemoveAdvertiserRequest {
- int32 advertiser_id = 1;
-}
-
-enum AdvertisingCallbackMsgType {
- ADVERTISING_SET_STARTED = 0;
- ADVERTISING_ENABLED = 1;
- ADVERTISING_DATA_SET = 2;
- SCAN_RESPONSE_DATA_SET = 3;
- ADVERTISING_PARAMETERS_UPDATED = 4;
- PERIODIC_ADVERTISING_PARAMETERS_UPDATED = 5;
- PERIODIC_ADVERTISING_DATA_SET = 6;
- PERIODIC_ADVERTISING_ENABLED = 7;
- OWN_ADDRESS_READ = 8;
-}
-
-message AdvertisingCallbackMsg {
- AdvertisingCallbackMsgType message_type = 1;
- uint32 advertiser_id = 2;
- AdvertisingStatus status = 3;
- uint32 data = 4;
-}
-
-message AddressMsg {
- AdvertisingCallbackMsgType message_type = 1;
- uint32 advertiser_id = 2;
- blueberry.facade.BluetoothAddressWithType address = 3;
-}
diff --git a/system/blueberry/facade/hci/le_initiator_address_facade.proto b/system/blueberry/facade/hci/le_initiator_address_facade.proto
deleted file mode 100644
index 8a0361cc7d..0000000000
--- a/system/blueberry/facade/hci/le_initiator_address_facade.proto
+++ /dev/null
@@ -1,28 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service LeInitiatorAddressFacade {
- rpc SetPrivacyPolicyForInitiatorAddress(PrivacyPolicy) returns (google.protobuf.Empty) {}
- rpc GetCurrentInitiatorAddress(google.protobuf.Empty) returns (blueberry.facade.BluetoothAddressWithType) {}
- rpc NewResolvableAddress(google.protobuf.Empty) returns (blueberry.facade.BluetoothAddressWithType) {}
-}
-
-enum AddressPolicy {
- POLICY_NOT_SET = 0x00;
- USE_PUBLIC_ADDRESS = 0x01;
- USE_STATIC_ADDRESS = 0x02;
- USE_NON_RESOLVABLE_ADDRESS = 0x03;
- USE_RESOLVABLE_ADDRESS = 0x04;
-}
-
-message PrivacyPolicy {
- AddressPolicy address_policy = 1;
- blueberry.facade.BluetoothAddressWithType address_with_type = 2;
- bytes rotation_irk = 3;
- uint64 minimum_rotation_time = 4;
- uint64 maximum_rotation_time = 5;
-}
diff --git a/system/blueberry/facade/hci/le_scanning_manager_facade.proto b/system/blueberry/facade/hci/le_scanning_manager_facade.proto
deleted file mode 100644
index 4dc14b5566..0000000000
--- a/system/blueberry/facade/hci/le_scanning_manager_facade.proto
+++ /dev/null
@@ -1,69 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.hci;
-
-import "google/protobuf/empty.proto";
-
-service LeScanningManagerFacade {
- rpc RegisterScanner(RegisterScannerRequest) returns (google.protobuf.Empty) {}
- rpc Unregister(UnregisterRequest) returns (google.protobuf.Empty) {}
- rpc Scan(ScanRequest) returns (google.protobuf.Empty) {}
- rpc SetScanParameters(SetScanParametersRequest) returns (google.protobuf.Empty) {}
- rpc FetchCallbackEvents(google.protobuf.Empty) returns (stream ScanningCallbackMsg) {}
- rpc FetchAdvertisingReports(google.protobuf.Empty) returns (stream AdvertisingReportMsg) {}
-}
-
-enum LeScanType {
- PASSIVE = 0x0;
- ACTIVE = 0x1;
-}
-
-enum ScanningCallbackMsgType {
- SCANNER_REGISTERED = 0;
- SET_SCANNER_PARAMETER_COMPLETE = 1;
- SCAN_RESULT = 2;
- TRACK_ADV_FOUND_LOST = 3;
- BATCH_SCAN_REPORTS = 4;
- BATCH_SCAN_THRESHOLD_CROSSED = 5;
- TIMEOUT = 6;
- FILTER_ENABLE = 7;
- FILTER_PARAMETER_SETUP = 8;
- FILTER_CONFIG = 9;
-}
-
-enum ScanningStatus {
- SCAN_SUCCESS = 0x00;
- SCAN_NO_RESOURCES = 0x80;
- SCAN_INTERNAL_ERROR = 0x85;
- SCAN_ILLEGAL_PARAMETER = 0x87;
-};
-
-message RegisterScannerRequest {
- uint32 uuid = 1;
-}
-
-message UnregisterRequest {
- uint32 scanner_id = 1;
-}
-
-message ScanRequest {
- bool start = 1;
-}
-
-message SetScanParametersRequest {
- uint32 scanner_id = 1;
- LeScanType scan_type = 2;
- uint32 scan_interval = 3;
- uint32 scan_window = 4;
- uint32 scan_phy = 5;
-}
-
-message AdvertisingReportMsg {
- bytes event = 1;
-}
-
-message ScanningCallbackMsg {
- ScanningCallbackMsgType message_type = 1;
- ScanningStatus status = 2;
- uint32 data = 3;
-}
diff --git a/system/blueberry/facade/l2cap/classic/facade.proto b/system/blueberry/facade/l2cap/classic/facade.proto
deleted file mode 100644
index 1017d507da..0000000000
--- a/system/blueberry/facade/l2cap/classic/facade.proto
+++ /dev/null
@@ -1,130 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.l2cap.classic;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service L2capClassicModuleFacade {
- rpc FetchConnectionComplete(google.protobuf.Empty) returns (stream ConnectionCompleteEvent) {
- // Testing Android Bluetooth stack only. Optional for other stack.
- }
- rpc FetchConnectionClose(google.protobuf.Empty) returns (stream ConnectionCloseEvent) {
- // Testing Android Bluetooth stack only. Optional for other stack.
- }
- rpc OpenChannel(OpenChannelRequest) returns (google.protobuf.Empty) {}
- rpc CloseChannel(CloseChannelRequest) returns (google.protobuf.Empty) {}
- rpc FetchL2capData(google.protobuf.Empty) returns (stream L2capPacket) {}
- rpc SetDynamicChannel(SetEnableDynamicChannelRequest) returns (google.protobuf.Empty) {}
- rpc SendDynamicChannelPacket(DynamicChannelPacket) returns (google.protobuf.Empty) {}
- rpc SetTrafficPaused(SetTrafficPausedRequest) returns (google.protobuf.Empty) {}
- rpc GetChannelQueueDepth(google.protobuf.Empty) returns (GetChannelQueueDepthResponse) {
- // Get the buffer size of channel queue end for L2CAP user (how many packets we can buffer
- // before L2CAP user dequeues.
- }
- rpc InitiateConnectionForSecurity(blueberry.facade.BluetoothAddress) returns (google.protobuf.Empty) {}
- rpc FetchSecurityConnectionEvents(google.protobuf.Empty) returns (stream LinkSecurityInterfaceCallbackEvent) {}
- rpc SecurityLinkEnsureAuthenticated(blueberry.facade.BluetoothAddress) returns (google.protobuf.Empty) {}
- rpc SecurityLinkHold(blueberry.facade.BluetoothAddress) returns (google.protobuf.Empty) {}
- rpc SecurityLinkDisconnect(blueberry.facade.BluetoothAddress) returns (google.protobuf.Empty) {}
- rpc SecurityLinkRelease(blueberry.facade.BluetoothAddress) returns (google.protobuf.Empty) {}
-}
-
-enum LinkSecurityInterfaceCallbackEventType {
- ON_CONNECTED = 0;
- ON_DISCONNECTED = 1;
- ON_AUTHENTICATION_COMPLETE = 2;
- ON_ENCRYPTION_CHANGE = 3;
- ON_READ_REMOTE_VERSION_INFO = 4;
- ON_READ_REMOTE_EXTENDED_FEATURES = 5;
-}
-
-message LinkSecurityInterfaceCallbackEvent {
- blueberry.facade.BluetoothAddress address = 1;
- LinkSecurityInterfaceCallbackEventType event_type = 2;
-}
-
-message RegisterChannelRequest {
- uint32 channel = 1;
-}
-
-message ConnectionCompleteEvent {
- blueberry.facade.BluetoothAddress remote = 1;
-}
-
-message ConnectionCloseEvent {
- blueberry.facade.BluetoothAddress remote = 1;
- uint32 reason = 2;
-}
-
-enum RetransmissionFlowControlMode {
- BASIC = 0;
- ERTM = 1;
- ERTM_OPTIONAL = 2;
-}
-
-message OpenChannelRequest {
- blueberry.facade.BluetoothAddress remote = 1;
- uint32 psm = 2;
- RetransmissionFlowControlMode mode = 3;
-}
-
-message CloseChannelRequest {
- uint32 psm = 1;
-}
-
-enum ChannelSignalEventType {
- OPEN = 0;
- CLOSE = 1;
- CONFIGURE = 2;
-}
-
-message ChannelSignalEvent {
- uint32 cid = 1;
- ChannelSignalEventType type = 2;
-}
-
-enum SendL2capPacketResultType {
- OK = 0;
- BAD_CID = 1;
-}
-
-message SendL2capPacketResult {
- SendL2capPacketResultType result_type = 1;
-}
-
-message L2capPacket {
- oneof channel_type {
- uint32 psm = 1;
- uint32 fixed_cid = 2;
- }
- bytes payload = 3;
-}
-
-message SetEnableDynamicChannelRequest {
- uint32 psm = 1;
- bool enable = 2;
- RetransmissionFlowControlMode retransmission_mode = 3;
-}
-
-message DynamicChannelPacket {
- blueberry.facade.BluetoothAddress remote = 1;
- uint32 psm = 2;
- bytes payload = 3;
-}
-
-message SetTrafficPausedRequest {
- bool paused = 1;
- uint32 psm = 2;
-}
-
-message GetChannelQueueDepthResponse {
- uint32 size = 1;
-}
-
-enum ClassicSecurityPolicy {
- ENCRYPTED_TRANSPORT = 0;
- AUTHENTICATED_ENCRYPTED_TRANSPORT = 1;
- BEST = 2;
- _SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK = 3;
-}
diff --git a/system/blueberry/facade/l2cap/le/facade.proto b/system/blueberry/facade/l2cap/le/facade.proto
deleted file mode 100644
index 842fde3a6a..0000000000
--- a/system/blueberry/facade/l2cap/le/facade.proto
+++ /dev/null
@@ -1,85 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.l2cap.le;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service L2capLeModuleFacade {
- rpc FetchL2capData(google.protobuf.Empty) returns (stream L2capPacket) {}
- // Initiate a credit based connection request and block until response is received for up to some timeout (2s)
- rpc OpenDynamicChannel(OpenDynamicChannelRequest) returns (OpenDynamicChannelResponse) {}
- rpc CloseDynamicChannel(CloseDynamicChannelRequest) returns (google.protobuf.Empty) {}
- rpc SetDynamicChannel(SetEnableDynamicChannelRequest) returns (google.protobuf.Empty) {}
- rpc SendDynamicChannelPacket(DynamicChannelPacket) returns (google.protobuf.Empty) {}
- rpc SetFixedChannel(SetEnableFixedChannelRequest) returns (google.protobuf.Empty) {}
- rpc SendFixedChannelPacket(FixedChannelPacket) returns (google.protobuf.Empty) {}
- rpc SendConnectionParameterUpdate(ConnectionParameter) returns (google.protobuf.Empty) {}
-}
-
-message L2capPacket {
- oneof channel_type {
- uint32 psm = 1;
- uint32 fixed_cid = 2;
- }
- bytes payload = 3;
-}
-
-message DynamicChannelOpenEvent {
- uint32 psm = 1;
- uint32 connection_response_result = 2;
-}
-
-message OpenDynamicChannelRequest {
- blueberry.facade.BluetoothAddressWithType remote = 1;
- uint32 psm = 2;
-}
-
-message OpenDynamicChannelResponse {
- uint32 status = 1;
-}
-
-message CloseDynamicChannelRequest {
- blueberry.facade.BluetoothAddressWithType remote = 1;
- uint32 psm = 2;
-}
-
-enum SecurityLevel {
- NO_SECURITY = 0;
- UNAUTHENTICATED_PAIRING_WITH_ENCRYPTION = 1;
- AUTHENTICATED_PAIRING_WITH_ENCRYPTION = 2;
- AUTHENTICATED_PAIRING_WITH_128_BIT_KEY = 3;
- AUTHORIZATION = 4;
-}
-
-message SetEnableDynamicChannelRequest {
- uint32 psm = 1;
- bool enable = 2;
- SecurityLevel security_level = 3;
-}
-
-message DynamicChannelPacket {
- blueberry.facade.BluetoothAddressWithType remote = 1;
- uint32 psm = 2;
- bytes payload = 3;
-}
-
-message SetEnableFixedChannelRequest {
- uint32 cid = 1;
- bool enable = 2;
-}
-
-message FixedChannelPacket {
- blueberry.facade.BluetoothAddressWithType remote = 1;
- uint32 cid = 2;
- bytes payload = 3;
-}
-
-message ConnectionParameter {
- uint32 conn_interval_min = 2;
- uint32 conn_interval_max = 3;
- uint32 conn_latency = 4;
- uint32 supervision_timeout = 5;
- uint32 min_ce_length = 6;
- uint32 max_ce_length = 7;
-}
diff --git a/system/blueberry/facade/neighbor/facade.proto b/system/blueberry/facade/neighbor/facade.proto
deleted file mode 100644
index 027855f031..0000000000
--- a/system/blueberry/facade/neighbor/facade.proto
+++ /dev/null
@@ -1,13 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade.neighbor;
-
-import "google/protobuf/empty.proto";
-
-service NeighborFacade {
- rpc EnablePageScan(EnableMsg) returns (google.protobuf.Empty) {}
-}
-
-message EnableMsg {
- bool enabled = 1;
-}
diff --git a/system/blueberry/facade/rootservice.proto b/system/blueberry/facade/rootservice.proto
deleted file mode 100644
index 0b9b164218..0000000000
--- a/system/blueberry/facade/rootservice.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-syntax = "proto3";
-
-package blueberry.facade;
-
-import "google/protobuf/empty.proto";
-import "blueberry/facade/common.proto";
-
-service RootFacade {
- rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
- rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
-}
-
-enum BluetoothModule {
- HAL = 0;
- HCI = 1;
- HCI_INTERFACES = 2;
- L2CAP = 3;
- SECURITY = 4;
- SHIM = 5;
-}
-
-message StartStackRequest {
- BluetoothModule module_under_test = 1;
-}
-
-message StartStackResponse {}
-
-message StopStackRequest {}
-
-message StopStackResponse {}
-
-service ReadOnlyProperty {
- rpc ReadLocalAddress(google.protobuf.Empty) returns (blueberry.facade.BluetoothAddress) {}
-}
diff --git a/system/blueberry/facade/topshim/facade.proto b/system/blueberry/facade/topshim/facade.proto
deleted file mode 100644
index c29891d49a..0000000000
--- a/system/blueberry/facade/topshim/facade.proto
+++ /dev/null
@@ -1,266 +0,0 @@
-syntax = "proto3";
-
-import "google/protobuf/empty.proto";
-
-package blueberry.facade.topshim;
-
-service AdapterService {
- rpc FetchEvents(FetchEventsRequest) returns (stream FetchEventsResponse) {}
- rpc ToggleStack(ToggleStackRequest) returns (ToggleStackResponse) {}
- rpc SetDiscoveryMode(SetDiscoveryModeRequest) returns (google.protobuf.Empty) {}
- rpc ClearEventFilter(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ClearEventMask(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ClearFilterAcceptList(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc DisconnectAllAcls(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc LeRand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetEventFilterConnectionSetupAllDevices(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc AllowWakeByHid(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc RestoreFilterAcceptList(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetDefaultEventMaskExcept(SetDefaultEventMaskExceptRequest) returns (google.protobuf.Empty) {}
- rpc SetEventFilterInquiryResultAllDevices(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetLocalIoCaps(SetLocalIoCapsRequest) returns (SetLocalIoCapsResponse) {}
- rpc ToggleDiscovery(ToggleDiscoveryRequest) returns (ToggleDiscoveryResponse) {}
-}
-
-service SecurityService {
- rpc RemoveBond(RemoveBondRequest) returns (google.protobuf.Empty) {}
- rpc GenerateLocalOobData(GenerateOobDataRequest) returns (google.protobuf.Empty) {}
- rpc CreateBond(CreateBondRequest) returns (CreateBondResponse) {}
-}
-
-service GattService {
- // Advertiser
- rpc RegisterAdvertiser(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc UnregisterAdvertiser(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc GetOwnAddress(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetParameters(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetData(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc AdvertisingEnable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc AdvertisingDisable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetPeriodicAdvertisingParameters(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetPeriodicAdvertisingData(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetPeriodicAdvertisingEnable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StartAdvertising(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StartAdvertisingSet(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-
- // Scanner
- rpc RegisterScanner(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc UnregisterScanner(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StartScan(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StopScan(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ScanFilterSetup(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ScanFilterAdd(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ScanFilterClear(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ScanFilterEnable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ScanFilterDisable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SetScanParameters(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc BatchScanConfigStorage(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc BatchScanEnable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc BatchScanDisable(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc BatchScanReadReports(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StartSync(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StopSync(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc CancelCreateSync(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc TransferSync(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc TransferSetInfo(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SyncTxParameters(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-
- // Gatt Client
- rpc RegisterClient(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc UnregisterClient(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ClientConnect(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ClientDisconnect(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc Refresh(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SearchService(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc BtifGattcDiscoverServiceByUuid(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ReadCharacteristic(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ReadUsingCharacteristicUuid(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc WriteCharacteristic(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ReadDescriptor(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc WriteDescriptor(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ExecuteWrite(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc RegisterForNotification(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc DeregisterForNotification(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ReadRemoteRssi(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc GetDeviceType(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ConfigureMtu(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ConnParameterUpdate(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ClientSetPreferredPhy(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ClientReadPhy(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc TestCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc GetGattDb(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-
- // Gatt Server
- rpc RegisterServer(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc UnregisterServer(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ServerConnect(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ServerDisconnect(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc AddService(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc StopService(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc DeleteService(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SendIndication(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc SendResponse(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ServerSetPreferredPhy(google.protobuf.Empty) returns (google.protobuf.Empty) {}
- rpc ServerReadPhy(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-}
-
-service HfpService {
- rpc StartSlc(StartSlcRequest) returns (google.protobuf.Empty) {}
- rpc StopSlc(StopSlcRequest) returns (google.protobuf.Empty) {}
- rpc ConnectAudio(ConnectAudioRequest) returns (google.protobuf.Empty) {}
- rpc DisconnectAudio(DisconnectAudioRequest) returns (google.protobuf.Empty) {}
- rpc SetVolume(SetVolumeRequest) returns (google.protobuf.Empty) {}
- rpc FetchEvents(FetchEventsRequest) returns (stream FetchEventsResponse) {}
-}
-
-service HfClientService {
- rpc StartSlc(StartSlcRequest) returns (StartSlcResponse) {}
- rpc StopSlc(StopSlcRequest) returns (StopSlcResponse) {}
- rpc ConnectAudio(ConnectAudioRequest) returns (ConnectAudioResponse) {}
- rpc DisconnectAudio(DisconnectAudioRequest) returns (DisconnectAudioResponse) {}
-}
-
-enum EventType {
- ADAPTER_STATE = 0;
- SSP_REQUEST = 1;
- LE_RAND = 2;
- GENERATE_LOCAL_OOB_DATA = 3;
- HFP_CONNECTION_STATE = 4;
- ADAPTER_PROPERTY = 5;
- DISCOVERY_STATE = 6;
- DEVICE_FOUND = 7;
- BOND_STATE = 8;
-}
-
-message FetchEventsRequest {}
-
-message FetchEventsResponse {
- EventType event_type = 1;
- string data = 2;
- // Storing all event related data as a key-value pair.
- map<string, EventData> params = 3;
-}
-
-message EventData {
- repeated string data = 1;
-}
-
-message ToggleStackRequest {
- bool start_stack = 1; // True for enable; false for disable
-}
-
-message ToggleStackResponse {}
-
-message SetDiscoveryModeRequest {
- bool enable_page_scan = 1;
- bool enable_inquiry_scan = 2;
-}
-
-service MediaService {
- rpc StartA2dp(StartA2dpRequest) returns (StartA2dpResponse) {}
- rpc A2dpSourceConnect(A2dpSourceConnectRequest) returns (A2dpSourceConnectResponse) {}
- rpc A2dpSourceSetActiveDevice(A2dpSourceSetActiveDeviceRequest) returns (A2dpSourceSetActiveDevicetResponse) {}
-}
-
-message StartA2dpRequest {
- bool start_a2dp_source = 1;
- bool start_a2dp_sink = 2;
-}
-
-message StartA2dpResponse {}
-
-message A2dpSourceConnectRequest {
- string address = 1;
-}
-
-message A2dpSourceConnectResponse {}
-
-message A2dpSourceSetActiveDeviceRequest {
- string address = 1;
-}
-
-message A2dpSourceSetActiveDevicetResponse {}
-
-message RemoveBondRequest {
- string address = 1;
-}
-
-message StartSlcRequest {
- Connection connection = 1;
-}
-
-message StartSlcResponse {
- int32 status = 1;
-}
-
-message StopSlcRequest {
- Connection connection = 1;
-}
-
-message StopSlcResponse {
- int32 status = 1;
-}
-
-message ConnectAudioRequest {
- Connection connection = 1;
- bool is_sco_offload_enabled = 2;
- int32 disabled_codecs = 3;
-}
-
-message ConnectAudioResponse {
- int32 status = 1;
-}
-
-message DisconnectAudioRequest {
- Connection connection = 1;
-}
-
-message DisconnectAudioResponse {
- int32 status = 1;
-}
-
-message SetVolumeRequest {
- Connection connection = 1;
- int32 volume = 2;
-}
-
-message SetDefaultEventMaskExceptRequest {
- uint64 mask = 1;
- uint64 le_mask = 2;
-}
-
-// A Token representing an ACL connection.
-// It's acquired via a Connect on the Host service (Bluetooth Core stack in our case).
-message Connection {
-// For our HFP APIs this would store the bluetooth address but staying consistent with Pandora naming.
- bytes cookie = 1;
-}
-
-message GenerateOobDataRequest {
- int32 transport = 1;
-}
-
-message SetLocalIoCapsRequest {
- int32 io_capability = 1;
-}
-
-message SetLocalIoCapsResponse {
- int32 status = 1;
-}
-
-message ToggleDiscoveryRequest {
- bool is_start = 1;
-}
-
-message ToggleDiscoveryResponse {
- int32 status = 1;
-}
-
-message CreateBondRequest {
- string address = 1;
- int32 transport = 2;
-}
-
-message CreateBondResponse {
- int32 status = 1;
-}
diff --git a/system/blueberry/tests/gd/cert/adb.py b/system/blueberry/tests/gd/cert/adb.py
deleted file mode 100644
index d28c24dfb2..0000000000
--- a/system/blueberry/tests/gd/cert/adb.py
+++ /dev/null
@@ -1,175 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import encodings
-import logging
-import shlex
-import shutil
-
-from mobly.controllers.android_device_lib.adb import AdbError
-from mobly.controllers.android_device_lib.adb import AdbProxy
-
-ROOT_USER_ID = '0'
-SHELL_USER_ID = '2000'
-UTF_8 = encodings.utf_8.getregentry().name
-
-
-class BlueberryAdbProxy(AdbProxy):
- """Proxy class for ADB.
-
- For syntactic reasons, the '-' in adb commands need to be replaced with
- '_'. Can directly execute adb commands on an object:
- >> adb = BlueberryAdbProxy(<serial>)
- >> adb.start_server()
- >> adb.devices() # will return the console output of "adb devices".
- """
-
- def __init__(self, serial="", ssh_connection=None):
- """Construct an instance of AdbProxy.
-
- Args:
- serial: str serial number of Android device from `adb devices`
- ssh_connection: SshConnection instance if the Android device is
- connected to a remote host that we can reach via SSH.
- """
- super().__init__(serial)
- self._server_local_port = None
- adb_path = shutil.which('adb')
- adb_cmd = [shlex.quote(adb_path)]
- if serial:
- adb_cmd.append("-s %s" % serial)
- if ssh_connection is not None:
- # Kill all existing adb processes on the remote host (if any)
- # Note that if there are none, then pkill exits with non-zero status
- ssh_connection.run("pkill adb", ignore_status=True)
- # Copy over the adb binary to a temp dir
- temp_dir = ssh_connection.run("mktemp -d").stdout.strip()
- ssh_connection.send_file(adb_path, temp_dir)
- # Start up a new adb server running as root from the copied binary.
- remote_adb_cmd = "%s/adb %s root" % (temp_dir, "-s %s" % serial if serial else "")
- ssh_connection.run(remote_adb_cmd)
- # Proxy a local port to the adb server port
- local_port = ssh_connection.create_ssh_tunnel(5037)
- self._server_local_port = local_port
-
- if self._server_local_port:
- adb_cmd.append("-P %d" % local_port)
- self.adb_str = " ".join(adb_cmd)
- self._ssh_connection = ssh_connection
-
- def get_user_id(self):
- """Returns the adb user. Either 2000 (shell) or 0 (root)."""
- return self.shell('id -u').decode(UTF_8).rstrip()
-
- def is_root(self, user_id=None):
- """Checks if the user is root.
-
- Args:
- user_id: if supplied, the id to check against.
- Returns:
- True if the user is root. False otherwise.
- """
- if not user_id:
- user_id = self.get_user_id()
- return user_id == ROOT_USER_ID
-
- def ensure_root(self):
- """Ensures the user is root after making this call.
-
- Note that this will still fail if the device is a user build, as root
- is not accessible from a user build.
-
- Returns:
- False if the device is a user build. True otherwise.
- """
- self.ensure_user(ROOT_USER_ID)
- return self.is_root()
-
- def ensure_user(self, user_id=SHELL_USER_ID):
- """Ensures the user is set to the given user.
-
- Args:
- user_id: The id of the user.
- """
- if self.is_root(user_id):
- self.root()
- else:
- self.unroot()
- self.wait_for_device()
- return self.get_user_id() == user_id
-
- def tcp_forward(self, host_port, device_port):
- """Starts tcp forwarding from localhost to this android device.
-
- Args:
- host_port: Port number to use on localhost
- device_port: Port number to use on the android device.
-
- Returns:
- Forwarded port on host as int or command output string on error
- """
- if self._ssh_connection:
- # We have to hop through a remote host first.
- # 1) Find some free port on the remote host's localhost
- # 2) Setup forwarding between that remote port and the requested
- # device port
- remote_port = self._ssh_connection.find_free_port()
- host_port = self._ssh_connection.create_ssh_tunnel(remote_port, local_port=host_port)
- try:
- output = self.forward(["tcp:%d" % host_port, "tcp:%d" % device_port])
- except AdbError as error:
- return error
- # If hinted_port is 0, the output will be the selected port.
- # Otherwise, there will be no output upon successfully
- # forwarding the hinted port.
- if not output:
- return host_port
- try:
- output_int = int(output)
- except ValueError:
- return output
- return output_int
-
- def remove_tcp_forward(self, host_port):
- """Stop tcp forwarding a port from localhost to this android device.
-
- Args:
- host_port: Port number to use on localhost
- """
- if self._ssh_connection:
- remote_port = self._ssh_connection.close_ssh_tunnel(host_port)
- if remote_port is None:
- logging.warning("Cannot close unknown forwarded tcp port: %d", host_port)
- return
- # The actual port we need to disable via adb is on the remote host.
- host_port = remote_port
- self.forward(["--remove", "tcp:%d" % host_port])
-
- def path_exists(self, path):
- """Check if a file path exists on an Android device
-
- :param path: file path, could be a directory
- :return: True if file path exists
- """
- try:
- ret = self.shell("ls {}".format(path))
- if ret is not None and len(ret) > 0:
- return True
- else:
- return False
- except AdbError as e:
- logging.debug("path {} does not exist, error={}".format(path, e))
- return False
diff --git a/system/blueberry/tests/gd/cert/asserts.py b/system/blueberry/tests/gd/cert/asserts.py
deleted file mode 100644
index 0be88498bd..0000000000
--- a/system/blueberry/tests/gd/cert/asserts.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2018 - 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.
-
-from mobly.asserts import *
-
-
-# Have an instance of unittest.TestCase so we could reuse some logic from
-# python's own unittest.
-# _ProxyTest is required because py2 does not allow instantiating
-# unittest.TestCase directly.
-class _ProxyTest(unittest.TestCase):
-
- def runTest(self):
- pass
-
-
-_pyunit_proxy = _ProxyTest()
-
-
-def assert_almost_equal(first, second, places=7, msg=None, delta=None, extras=None):
- """
- Assert FIRST to be within +/- DELTA to SECOND, otherwise fail the
- test.
- :param first: The first argument, LHS
- :param second: The second argument, RHS
- :param places: For floating points, how many decimal places to look into
- :param msg: Message to display on failure
- :param delta: The +/- first and second could be apart from each other
- :param extras: Extra object passed to test failure handler
- :return:
- """
- my_msg = None
- try:
- if delta:
- _pyunit_proxy.assertAlmostEqual(first, second, msg=msg, delta=delta)
- else:
- _pyunit_proxy.assertAlmostEqual(first, second, places=places, msg=msg)
- except Exception as e:
- my_msg = str(e)
- if msg:
- my_msg = "%s %s" % (my_msg, msg)
- # This is a hack to remove the stacktrace produced by the above exception.
- if my_msg is not None:
- fail(my_msg, extras=extras)
diff --git a/system/blueberry/tests/gd/cert/async_subprocess_logger.py b/system/blueberry/tests/gd/cert/async_subprocess_logger.py
deleted file mode 100644
index 79a85f7984..0000000000
--- a/system/blueberry/tests/gd/cert/async_subprocess_logger.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import concurrent.futures
-import logging
-import re
-import subprocess
-from blueberry.tests.gd.cert.os_utils import TerminalColor
-from contextlib import ExitStack
-
-
-class AsyncSubprocessLogger:
- """
- An asynchronous logger for subprocesses.Popen object's STDOUT
-
- Contains threading functionality that allows asynchronous handling of lines
- from STDOUT from subprocess.Popen
- """
- WAIT_TIMEOUT_SECONDS = 10
- PROCESS_TAG_MIN_WIDTH = 24
-
- def __init__(self,
- process: subprocess.Popen,
- log_file_paths,
- log_to_stdout=False,
- tag=None,
- color: TerminalColor = None):
- """
- :param process: a subprocess.Popen object with STDOUT
- :param log_file_paths: list of log files to redirect log to
- :param log_to_stdout: whether to dump logs to stdout in the format of
- "[tag] logline"
- :param tag: tag to be used in above format
- :param color: when dumping to stdout, what color to use for tag
- """
- if not process:
- raise ValueError("process cannot be None")
- if not process.stdout:
- raise ValueError("process.stdout cannot be None")
- if log_to_stdout:
- if not tag or type(tag) is not str:
- raise ValueError("When logging to stdout, log tag must be set")
- self.log_file_paths = log_file_paths
- self.log_to_stdout = log_to_stdout
- self.tag = tag
- self.color = color
- self.process = process
- self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
- self.future = self.executor.submit(self.__logging_loop)
-
- def stop(self):
- """
- Stop this logger and this object can no longer be used after this call
- """
- try:
- result = self.future.result(timeout=self.WAIT_TIMEOUT_SECONDS)
- if result:
- logging.error("logging thread %s produced an error when executing: %s" % (self.tag, str(result)))
- except concurrent.futures.TimeoutError:
- logging.error("logging thread %s failed to finish after %d seconds" % (self.tag, self.WAIT_TIMEOUT_SECONDS))
- self.executor.shutdown(wait=False)
-
- def __logging_loop(self):
- if self.color:
- loggableTag = "[%s%s%s]" % (self.color, self.tag, TerminalColor.END)
- else:
- loggableTag = "[%s]" % self.tag
- tagLength = len(re.sub('[^\w\s]', '', loggableTag))
- if tagLength < self.PROCESS_TAG_MIN_WIDTH:
- loggableTag += " " * (self.PROCESS_TAG_MIN_WIDTH - tagLength)
- with ExitStack() as stack:
- log_files = [stack.enter_context(open(file_path, 'w')) for file_path in self.log_file_paths]
- for line in self.process.stdout:
- for log_file in log_files:
- log_file.write(line)
- if self.log_to_stdout:
- print("{}{}".format(loggableTag, line.strip()))
diff --git a/system/blueberry/tests/gd/cert/behavior.py b/system/blueberry/tests/gd/cert/behavior.py
deleted file mode 100644
index 10fc494a73..0000000000
--- a/system/blueberry/tests/gd/cert/behavior.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from abc import ABC, abstractmethod
-from datetime import datetime, timedelta
-from mobly import signals
-from threading import Condition
-
-from blueberry.tests.gd.cert.event_stream import static_remaining_time_delta
-from blueberry.tests.gd.cert.truth import assertThat
-
-
-class IHasBehaviors(ABC):
-
- @abstractmethod
- def get_behaviors(self):
- pass
-
-
-def anything():
- return lambda obj: True
-
-
-def when(has_behaviors):
- assertThat(isinstance(has_behaviors, IHasBehaviors)).isTrue()
- return has_behaviors.get_behaviors()
-
-
-def IGNORE_UNHANDLED(obj):
- pass
-
-
-class SingleArgumentBehavior(object):
-
- def __init__(self, reply_stage_factory):
- self._reply_stage_factory = reply_stage_factory
- self._instances = []
- self._invoked_obj = []
- self._invoked_condition = Condition()
- self.set_default_to_crash()
-
- def begin(self, matcher):
- return PersistenceStage(self, matcher, self._reply_stage_factory)
-
- def append(self, behavior_instance):
- self._instances.append(behavior_instance)
-
- def set_default(self, fn):
- assertThat(fn).isNotNone()
- self._default_fn = fn
-
- def set_default_to_crash(self):
- self._default_fn = None
-
- def set_default_to_ignore(self):
- self._default_fn = IGNORE_UNHANDLED
-
- def run(self, obj):
- for instance in self._instances:
- if instance.try_run(obj):
- self.__obj_invoked(obj)
- return
- if self._default_fn is not None:
- # IGNORE_UNHANDLED is also a default fn
- self._default_fn(obj)
- self.__obj_invoked(obj)
- else:
- raise signals.TestFailure(
- "%s: behavior for %s went unhandled" % (self._reply_stage_factory().__class__.__name__, obj),
- extras=None)
-
- def __obj_invoked(self, obj):
- self._invoked_condition.acquire()
- self._invoked_obj.append(obj)
- self._invoked_condition.notify()
- self._invoked_condition.release()
-
- def wait_until_invoked(self, matcher, times, timeout):
- end_time = datetime.now() + timeout
- invoked_times = 0
- while datetime.now() < end_time and invoked_times < times:
- remaining = static_remaining_time_delta(end_time)
- invoked_times = sum((matcher(i) for i in self._invoked_obj))
- self._invoked_condition.acquire()
- self._invoked_condition.wait(remaining.total_seconds())
- self._invoked_condition.release()
- return invoked_times == times
-
-
-class PersistenceStage(object):
-
- def __init__(self, behavior, matcher, reply_stage_factory):
- self._behavior = behavior
- self._matcher = matcher
- self._reply_stage_factory = reply_stage_factory
-
- def then(self, times=1):
- reply_stage = self._reply_stage_factory()
- reply_stage.init(self._behavior, self._matcher, times)
- return reply_stage
-
- def always(self):
- return self.then(times=-1)
-
-
-class ReplyStage(object):
-
- def init(self, behavior, matcher, persistence):
- self._behavior = behavior
- self._matcher = matcher
- self._persistence = persistence
-
- def _commit(self, fn):
- self._behavior.append(BehaviorInstance(self._matcher, self._persistence, fn))
-
-
-class BehaviorInstance(object):
-
- def __init__(self, matcher, persistence, fn):
- self._matcher = matcher
- self._persistence = persistence
- self._fn = fn
- self._called_count = 0
-
- def try_run(self, obj):
- if not self._matcher(obj):
- return False
- if self._persistence >= 0:
- if self._called_count >= self._persistence:
- return False
- self._called_count += 1
- self._fn(obj)
- return True
-
-
-class BoundVerificationStage(object):
-
- def __init__(self, behavior, matcher, timeout):
- self._behavior = behavior
- self._matcher = matcher
- self._timeout = timeout
-
- def times(self, times=1):
- return self._behavior.wait_until_invoked(self._matcher, times, self._timeout)
-
-
-class WaitForBehaviorSubject(object):
-
- def __init__(self, behaviors, timeout):
- self._behaviors = behaviors
- self._timeout = timeout
-
- def __getattr__(self, item):
- behavior = getattr(self._behaviors, item + "_behavior")
- t = self._timeout
- return lambda matcher: BoundVerificationStage(behavior, matcher, t)
-
-
-def wait_until(i_has_behaviors, timeout=timedelta(seconds=3)):
- return WaitForBehaviorSubject(i_has_behaviors.get_behaviors(), timeout)
diff --git a/system/blueberry/tests/gd/cert/capture.py b/system/blueberry/tests/gd/cert/capture.py
deleted file mode 100644
index e37dc7dbbc..0000000000
--- a/system/blueberry/tests/gd/cert/capture.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-
-class Capture(object):
- """
- Wrap a match function and use in its place, to capture the value
- that matched. Specify an optional |capture_fn| to transform the
- captured value.
- """
-
- def __init__(self, match_fn, capture_fn=None):
- self._match_fn = match_fn
- self._capture_fn = capture_fn
- self._value = None
-
- def __call__(self, obj):
- if self._match_fn(obj) != True:
- return False
-
- if self._capture_fn is not None:
- self._value = self._capture_fn(obj)
- else:
- self._value = obj
- return True
-
- def get(self):
- return self._value
diff --git a/system/blueberry/tests/gd/cert/captures.py b/system/blueberry/tests/gd/cert/captures.py
deleted file mode 100644
index 7358ad1e70..0000000000
--- a/system/blueberry/tests/gd/cert/captures.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from blueberry.tests.gd.cert.capture import Capture
-from blueberry.tests.gd.cert.matchers import HciMatchers
-from blueberry.tests.gd.cert.matchers import SecurityMatchers
-import hci_packets as hci
-
-
-class HalCaptures(object):
-
- @staticmethod
- def ReadBdAddrCompleteCapture():
- return Capture(lambda packet: packet.payload[0:5] == b'\x0e\x0a\x01\x09\x10',
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def ConnectionRequestCapture():
- return Capture(lambda packet: packet.payload[0:2] == b'\x04\x0a',
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def ConnectionCompleteCapture():
- return Capture(lambda packet: packet.payload[0:3] == b'\x03\x0b\x00',
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def DisconnectionCompleteCapture():
- return Capture(lambda packet: packet.payload[0:2] == b'\x05\x04',
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def LeConnectionCompleteCapture():
- return Capture(
- lambda packet: packet.payload[0] == 0x3e and (packet.payload[2] == 0x01 or packet.payload[2] == 0x0a),
- lambda packet: hci.Event.parse_all(packet.payload))
-
-
-class HciCaptures(object):
-
- @staticmethod
- def ReadLocalOobDataCompleteCapture():
- return Capture(
- HciMatchers.CommandComplete(hci.OpCode.READ_LOCAL_OOB_DATA),
- lambda packet: HciMatchers.ExtractMatchingCommandComplete(packet.payload, hci.OpCode.READ_LOCAL_OOB_DATA))
-
- @staticmethod
- def ReadLocalOobExtendedDataCompleteCapture():
- return Capture(
- HciMatchers.CommandComplete(hci.OpCode.READ_LOCAL_OOB_EXTENDED_DATA), lambda packet: HciMatchers.
- ExtractMatchingCommandComplete(packet.payload, hci.OpCode.READ_LOCAL_OOB_EXTENDED_DATA))
-
- @staticmethod
- def ReadBdAddrCompleteCapture():
- return Capture(HciMatchers.CommandComplete(hci.OpCode.READ_BD_ADDR),
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def ConnectionRequestCapture():
- return Capture(HciMatchers.EventWithCode(hci.EventCode.CONNECTION_REQUEST),
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def ConnectionCompleteCapture():
- return Capture(HciMatchers.EventWithCode(hci.EventCode.CONNECTION_COMPLETE),
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def DisconnectionCompleteCapture():
- return Capture(HciMatchers.EventWithCode(hci.EventCode.DISCONNECTION_COMPLETE),
- lambda packet: hci.Event.parse_all(packet.payload))
-
- @staticmethod
- def LeConnectionCompleteCapture():
- return Capture(HciMatchers.LeConnectionComplete(),
- lambda packet: HciMatchers.ExtractLeConnectionComplete(packet.payload))
-
- @staticmethod
- def SimplePairingCompleteCapture():
- return Capture(HciMatchers.EventWithCode(hci.EventCode.SIMPLE_PAIRING_COMPLETE),
- lambda packet: hci.Event.parse_all(packet.payload))
diff --git a/system/blueberry/tests/gd/cert/cert_self_test.py b/system/blueberry/tests/gd/cert/cert_self_test.py
deleted file mode 100644
index 5ccd8f9ecc..0000000000
--- a/system/blueberry/tests/gd/cert/cert_self_test.py
+++ /dev/null
@@ -1,659 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-import logging
-import time
-import traceback
-from datetime import datetime, timedelta
-from threading import Timer
-
-from blueberry.tests.gd.cert.behavior import when, wait_until
-from blueberry.tests.gd.cert.behavior import IHasBehaviors
-from blueberry.tests.gd.cert.behavior import anything
-from blueberry.tests.gd.cert.behavior import SingleArgumentBehavior
-from blueberry.tests.gd.cert.behavior import ReplyStage
-from blueberry.tests.gd.cert.event_stream import EventStream, FilteringEventStream
-from blueberry.tests.gd.cert.metadata import metadata
-from blueberry.tests.gd.cert.truth import assertThat
-import hci_packets as hci
-
-from mobly import asserts
-from mobly import signals
-from mobly import test_runner
-from mobly import base_test
-
-
-class BogusProto:
-
- class BogusType:
-
- def __init__(self):
- self.name = "BogusProto"
- self.is_extension = False
- self.cpp_type = False
-
- def type(self):
- return 'BogusRpc'
-
- def label(self):
- return "label"
-
- class BogusDescriptor:
-
- def __init__(self, name):
- self.full_name = name
-
- def __init__(self, value):
- self.value_ = value
- self.DESCRIPTOR = BogusProto.BogusDescriptor(str(value))
-
- def __str__(self):
- return "BogusRpc value = " + str(self.value_)
-
- def ListFields(self):
- for field in [BogusProto.BogusType()]:
- yield [field, self.value_]
-
-
-class FetchEvents:
-
- def __init__(self, events, delay_ms):
- self.events_ = events
- self.sleep_time_ = (delay_ms * 1.0) / 1000
- self.index_ = 0
- self.done_ = False
- self.then_ = datetime.now()
-
- def __iter__(self):
- for event in self.events_:
- time.sleep(self.sleep_time_)
- if self.done_:
- return
- logging.debug("yielding %d" % event)
- yield BogusProto(event)
-
- def done(self):
- return self.done_
-
- def cancel(self):
- logging.debug("cancel")
- self.done_ = True
- return None
-
-
-class TestBehaviors(object):
-
- def __init__(self, parent):
- self.test_request_behavior = SingleArgumentBehavior(lambda: TestBehaviors.TestRequestReplyStage(parent))
-
- def test_request(self, matcher):
- return self.test_request_behavior.begin(matcher)
-
- class TestRequestReplyStage(ReplyStage):
-
- def __init__(self, parent):
- self._parent = parent
-
- def increment_count(self):
- self._commit(lambda obj: self._increment_count(obj))
- return self
-
- def _increment_count(self, obj):
- self._parent.count += 1
- self._parent.captured.append(obj)
-
-
-class ObjectWithBehaviors(IHasBehaviors):
-
- def __init__(self):
- self.behaviors = TestBehaviors(self)
- self.count = 0
- self.captured = []
- self.unhandled_count = 0
-
- def get_behaviors(self):
- return self.behaviors
-
- def increment_unhandled(self):
- self.unhandled_count += 1
-
-
-class CertSelfTest(base_test.BaseTestClass):
-
- def setup_test(self):
- return True
-
- def teardown_test(self):
- return True
-
- def test_assert_occurs_at_least_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3, 1, 2, 3], delay_ms=40)) as event_stream:
- event_stream.assert_event_occurs(lambda data: data.value_ == 1,
- timeout=timedelta(milliseconds=300),
- at_least_times=2)
-
- def test_assert_occurs_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- event_stream.assert_event_occurs(lambda data: data.value_ == 1, timeout=timedelta(seconds=1))
-
- def test_assert_occurs_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- event_stream.assert_event_occurs(lambda data: data.value_ == 4, timeout=timedelta(seconds=1))
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_assert_occurs_at_most_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3, 4], delay_ms=50)) as event_stream:
- event_stream.assert_event_occurs_at_most(lambda data: data.value_ < 4,
- timeout=timedelta(seconds=1),
- at_most_times=3)
-
- def test_assert_occurs_at_most_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3, 4], delay_ms=50)) as event_stream:
- event_stream.assert_event_occurs_at_most(lambda data: data.value_ > 1,
- timeout=timedelta(seconds=1),
- at_most_times=2)
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_skip_a_test(self):
- asserts.skip("Skipping this test because it's blocked by b/xyz")
- assert False
-
- def test_nested_packets(self):
- handle = 123
- inside = hci.ReadScanEnable()
- logging.debug(inside.serialize())
- logging.debug("building outside")
- outside = hci.Acl(handle=handle,
- packet_boundary_flag=hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- broadcast_flag=hci.BroadcastFlag.POINT_TO_POINT,
- payload=inside.serialize())
- logging.debug(outside.serialize())
- logging.debug("Done!")
-
- def test_assertThat_boolean_success(self):
- assertThat(True).isTrue()
- assertThat(False).isFalse()
-
- def test_assertThat_boolean_falseIsTrue(self):
- try:
- assertThat(False).isTrue()
- except Exception as e:
- return True
- return False
-
- def test_assertThat_boolean_trueIsFalse(self):
- try:
- assertThat(True).isFalse()
- except Exception as e:
- return True
- return False
-
- def test_assertThat_object_success(self):
- assertThat("this").isEqualTo("this")
- assertThat("this").isNotEqualTo("that")
- assertThat(None).isNone()
- assertThat("this").isNotNone()
-
- def test_assertThat_object_isEqualToFails(self):
- try:
- assertThat("this").isEqualTo("that")
- except Exception as e:
- return True
- return False
-
- def test_assertThat_object_isNotEqualToFails(self):
- try:
- assertThat("this").isNotEqualTo("this")
- except Exception as e:
- return True
- return False
-
- def test_assertThat_object_isNoneFails(self):
- try:
- assertThat("this").isNone()
- except Exception as e:
- return True
- return False
-
- def test_assertThat_object_isNotNoneFails(self):
- try:
- assertThat(None).isNotNone()
- except Exception as e:
- return True
- return False
-
- def test_assertThat_eventStream_emits_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 1)
-
- def test_assertThat_eventStream_emits_then_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 1).then(lambda data: data.value_ == 3)
-
- def test_assertThat_eventStream_emits_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 4)
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_assertThat_eventStream_emits_then_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 1).emits(lambda data: data.value_ == 4)
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_assertThat_eventStream_emitsInOrder_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 1, lambda data: data.value_ == 2).inOrder()
-
- def test_assertThat_eventStream_emitsInAnyOrder_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(
- lambda data: data.value_ == 2,
- lambda data: data.value_ == 1).inAnyOrder().then(lambda data: data.value_ == 3)
-
- def test_assertThat_eventStream_emitsInOrder_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 2, lambda data: data.value_ == 1).inOrder()
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_assertThat_eventStream_emitsInAnyOrder_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emits(lambda data: data.value_ == 4,
- lambda data: data.value_ == 1).inAnyOrder()
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_assertThat_emitsNone_passes(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emitsNone(lambda data: data.value_ == 4, timeout=timedelta(seconds=0.15)).thenNone(
- lambda data: data.value_ == 5, timeout=timedelta(seconds=0.15))
-
- def test_assertThat_emitsNone_passes_after_1_second(self):
- with EventStream(FetchEvents(events=[1, 2, 3, 4], delay_ms=400)) as event_stream:
- assertThat(event_stream).emitsNone(lambda data: data.value_ == 4, timeout=timedelta(seconds=1))
-
- def test_assertThat_emitsNone_fails(self):
- try:
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- assertThat(event_stream).emitsNone(lambda data: data.value_ == 2, timeout=timedelta(seconds=1))
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_assertThat_emitsNone_zero_passes(self):
- with EventStream(FetchEvents(events=[], delay_ms=50)) as event_stream:
- assertThat(event_stream).emitsNone(timeout=timedelta(milliseconds=10)).thenNone(timeout=timedelta(
- milliseconds=10))
-
- def test_assertThat_emitsNone_zero_passes_after_one_second(self):
- with EventStream(FetchEvents([1], delay_ms=1500)) as event_stream:
- assertThat(event_stream).emitsNone(timeout=timedelta(seconds=1.0))
-
- def test_assertThat_emitsNone_zero_fails(self):
- try:
- with EventStream(FetchEvents(events=[17], delay_ms=50)) as event_stream:
- assertThat(event_stream).emitsNone(timeout=timedelta(seconds=1))
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_filtering_event_stream_none_filter_function(self):
- with EventStream(FetchEvents(events=[1, 2, 3], delay_ms=50)) as event_stream:
- filtered_event_stream = FilteringEventStream(event_stream, None)
- assertThat(filtered_event_stream) \
- .emits(lambda data: data.value_ == 1) \
- .then(lambda data: data.value_ == 3)
-
- def test_metadata_empty(self):
-
- @metadata()
- def simple_pass_test(arg):
- pass
-
- try:
- simple_pass_test(1)
- except signals.TestFailure:
- pass
- except Exception as e:
- asserts.fail("@metadata() should only raise signals.TestFailure, "
- "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
- else:
- asserts.fail("@metadata() should not work")
-
- def test_metadata_empty_no_function_call(self):
-
- @metadata
- def simple_pass_test(arg):
- pass
-
- try:
- simple_pass_test(1)
- except signals.TestFailure:
- pass
- except Exception as e:
- asserts.fail("@metadata should only raise signals.TestFailure, "
- "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
- else:
- asserts.fail("@metadata should not work")
-
- def test_metadata_pts_missing_id(self):
-
- @metadata(pts_test_name="Hello world")
- def simple_pass_test(arg):
- pass
-
- try:
- simple_pass_test(1)
- except signals.TestFailure:
- pass
- except Exception as e:
- asserts.fail("should only raise signals.TestFailure, "
- "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
- else:
- asserts.fail("missing pts_test_id should not work")
-
- def test_metadata_pts_missing_name(self):
-
- @metadata(pts_test_id="A/B/C")
- def simple_pass_test(arg):
- pass
-
- try:
- simple_pass_test(1)
- except signals.TestFailure:
- pass
- except Exception as e:
- asserts.fail("should only raise signals.TestFailure, "
- "but raised %s with msg %s instead" % (e.__class__.__name__, str(e)))
- else:
- asserts.fail("missing pts_test_name should not work")
-
- def test_metadata_pts_test_id_and_description(self):
-
- @metadata(pts_test_id="A/B/C", pts_test_name="Hello world")
- def simple_pass_test(arg):
- pass
-
- try:
- simple_pass_test(1)
- except signals.TestPass as e:
- asserts.assert_true("pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras)))
- asserts.assert_equal(e.extras["pts_test_id"], "A/B/C")
- asserts.assert_true("pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras)))
- asserts.assert_equal(e.extras["pts_test_name"], "Hello world")
- else:
- asserts.fail("Must throw an exception using @metadata decorator")
-
- def test_metadata_test_with_exception_stacktrace(self):
-
- @metadata(pts_test_id="A/B/C", pts_test_name="Hello world")
- def simple_fail_test(failure_argument):
- raise ValueError(failure_argument)
-
- try:
- simple_fail_test("BEEFBEEF")
- except signals.TestError as e:
- asserts.assert_true("pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras)))
- asserts.assert_equal(e.extras["pts_test_id"], "A/B/C")
- asserts.assert_true("pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras)))
- asserts.assert_equal(e.extras["pts_test_name"], "Hello world")
- trace_str = traceback.format_exc()
- asserts.assert_true("raise ValueError(failure_argument)" in trace_str,
- msg="Failed test method not in error stack trace: %s" % trace_str)
- else:
- asserts.fail("Must throw an exception using @metadata decorator")
-
- def test_fluent_behavior_simple(self):
- thing = ObjectWithBehaviors()
-
- when(thing).test_request(anything()).then().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
-
- assertThat(thing.count).isEqualTo(1)
- assertThat(thing.captured).isEqualTo(["A"])
-
- def test_fluent_behavior__then_single__captures_one(self):
- thing = ObjectWithBehaviors()
-
- thing.behaviors.test_request_behavior.set_default_to_ignore()
-
- when(thing).test_request(anything()).then().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("A")
-
- assertThat(thing.count).isEqualTo(1)
- assertThat(thing.captured).isEqualTo(["A"])
-
- def test_fluent_behavior__then_times__captures_all(self):
- thing = ObjectWithBehaviors()
-
- when(thing).test_request(anything()).then(times=3).increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("B")
- thing.behaviors.test_request_behavior.run("C")
-
- assertThat(thing.count).isEqualTo(3)
- assertThat(thing.captured).isEqualTo(["A", "B", "C"])
-
- def test_fluent_behavior__always__captures_all(self):
- thing = ObjectWithBehaviors()
-
- when(thing).test_request(anything()).always().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("B")
- thing.behaviors.test_request_behavior.run("C")
-
- assertThat(thing.count).isEqualTo(3)
- assertThat(thing.captured).isEqualTo(["A", "B", "C"])
-
- def test_fluent_behavior__matcher__captures_relevant(self):
- thing = ObjectWithBehaviors()
- thing.behaviors.test_request_behavior.set_default_to_ignore()
-
- when(thing).test_request(lambda obj: obj == "B").always().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("B")
- thing.behaviors.test_request_behavior.run("C")
-
- assertThat(thing.count).isEqualTo(1)
- assertThat(thing.captured).isEqualTo(["B"])
-
- def test_fluent_behavior__then_repeated__captures_relevant(self):
- thing = ObjectWithBehaviors()
- thing.behaviors.test_request_behavior.set_default_to_ignore()
-
- when(thing).test_request(anything()).then().increment_count().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("B")
- thing.behaviors.test_request_behavior.run("A")
-
- assertThat(thing.count).isEqualTo(2)
- assertThat(thing.captured).isEqualTo(["A", "B"])
-
- def test_fluent_behavior__fallback__captures_relevant(self):
- thing = ObjectWithBehaviors()
- thing.behaviors.test_request_behavior.set_default_to_ignore()
-
- when(thing).test_request(lambda obj: obj == "B").then(times=1).increment_count()
- when(thing).test_request(lambda obj: obj == "C").always().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("B")
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("C")
- thing.behaviors.test_request_behavior.run("B")
- thing.behaviors.test_request_behavior.run("C")
-
- assertThat(thing.count).isEqualTo(3)
- assertThat(thing.captured).isEqualTo(["B", "C", "C"])
-
- def test_fluent_behavior__default_unhandled_crash(self):
- thing = ObjectWithBehaviors()
-
- when(thing).test_request(anything()).then().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- try:
- thing.behaviors.test_request_behavior.run("A")
- except Exception as e:
- logging.debug(e)
- return True # Failed as expected
- return False
-
- def test_fluent_behavior__set_default_works(self):
- thing = ObjectWithBehaviors()
- thing.behaviors.test_request_behavior.set_default(lambda obj: thing.increment_unhandled())
-
- when(thing).test_request(anything()).then().increment_count()
-
- thing.behaviors.test_request_behavior.run("A")
- thing.behaviors.test_request_behavior.run("A")
- assertThat(thing.unhandled_count).isEqualTo(1)
-
- def test_fluent_behavior__wait_until_done(self):
- thing = ObjectWithBehaviors()
- is_a = lambda obj: obj == "A"
- when(thing).test_request(is_a).then().increment_count()
-
- closure = lambda: thing.behaviors.test_request_behavior.run("A")
- t = Timer(0.5, closure)
- t.start()
-
- wait_until(thing).test_request(is_a).times(1)
- assertThat(thing.count).isEqualTo(1)
- assertThat(thing.captured).isEqualTo(["A"])
-
- def test_fluent_behavior__wait_until_done_different_lambda(self):
- thing = ObjectWithBehaviors()
- when(thing).test_request(lambda obj: obj == "A").then().increment_count()
-
- closure = lambda: thing.behaviors.test_request_behavior.run("A")
- t = Timer(0.5, closure)
- t.start()
-
- wait_until(thing).test_request(lambda obj: obj == "A").times(1)
- assertThat(thing.count).isEqualTo(1)
- assertThat(thing.captured).isEqualTo(["A"])
-
- def test_fluent_behavior__wait_until_done_anything(self):
- thing = ObjectWithBehaviors()
- when(thing).test_request(lambda obj: obj == "A").then().increment_count()
-
- closure = lambda: thing.behaviors.test_request_behavior.run("A")
- t = Timer(0.5, closure)
- t.start()
-
- wait_until(thing).test_request(anything()).times(1)
- assertThat(thing.count).isEqualTo(1)
- assertThat(thing.captured).isEqualTo(["A"])
-
- def test_fluent_behavior__wait_until_done_not_happened(self):
- thing = ObjectWithBehaviors()
- thing.behaviors.test_request_behavior.set_default_to_ignore()
- when(thing).test_request(lambda obj: obj == "A").then().increment_count()
-
- closure = lambda: thing.behaviors.test_request_behavior.run("B")
- t = Timer(0.5, closure)
- t.start()
- assertThat(wait_until(thing).test_request(lambda obj: obj == "A").times(1)).isFalse()
-
- def test_fluent_behavior__wait_until_done_with_default(self):
- thing = ObjectWithBehaviors()
- thing.behaviors.test_request_behavior.set_default(lambda obj: thing.increment_unhandled())
-
- closure = lambda: thing.behaviors.test_request_behavior.run("A")
- t = Timer(0.5, closure)
- t.start()
-
- wait_until(thing).test_request(anything()).times(1)
- assertThat(thing.unhandled_count).isEqualTo(1)
-
- def test_fluent_behavior__wait_until_done_two_events_AA(self):
- thing = ObjectWithBehaviors()
- when(thing).test_request(lambda obj: obj == "A").then().increment_count().increment_count()
-
- closure1 = lambda: thing.behaviors.test_request_behavior.run("A")
- t1 = Timer(0.5, closure1)
- t1.start()
- closure2 = lambda: thing.behaviors.test_request_behavior.run("A")
- t2 = Timer(0.5, closure2)
- t2.start()
-
- wait_until(thing).test_request(lambda obj: obj == "A").times(2)
- assertThat(thing.count).isEqualTo(2)
- assertThat(thing.captured).isEqualTo(["A", "A"])
-
- def test_fluent_behavior__wait_until_done_two_events_AB(self):
- thing = ObjectWithBehaviors()
- when(thing).test_request(anything()).always().increment_count()
-
- closure1 = lambda: thing.behaviors.test_request_behavior.run("A")
- t1 = Timer(0.5, closure1)
- t1.start()
- closure2 = lambda: thing.behaviors.test_request_behavior.run("B")
- t2 = Timer(1, closure2)
- t2.start()
-
- wait_until(thing).test_request(anything()).times(2)
- assertThat(thing.count).isEqualTo(2)
- assertThat(thing.captured).isEqualTo(["A", "B"])
-
- def test_fluent_behavior__wait_until_done_only_one_event_is_done(self):
- thing = ObjectWithBehaviors()
- when(thing).test_request(anything()).always().increment_count()
-
- closure1 = lambda: thing.behaviors.test_request_behavior.run("A")
- t1 = Timer(1, closure1)
- t1.start()
- closure2 = lambda: thing.behaviors.test_request_behavior.run("B")
- t2 = Timer(3, closure2)
- t2.start()
- assertThat(wait_until(thing).test_request(lambda obj: obj == "A").times(2)).isFalse()
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/cert/closable.py b/system/blueberry/tests/gd/cert/closable.py
deleted file mode 100644
index 06a6d0df18..0000000000
--- a/system/blueberry/tests/gd/cert/closable.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-import time
-from abc import ABC, abstractmethod
-import logging
-
-
-class Closable(ABC):
-
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- try:
- self.close()
- except Exception:
- logging.warning("Failed to close or already closed")
- return traceback is None
-
- def __del__(self):
- try:
- self.close()
- except Exception:
- logging.warning("Failed to close or already closed")
-
- @abstractmethod
- def close(self):
- pass
-
-
-def safeClose(closable):
- if closable is not None:
- closable.close()
- # sleep for 100ms because GrpcEventQueue takes at most 100 ms to close
- time.sleep(0.1)
diff --git a/system/blueberry/tests/gd/cert/context.py b/system/blueberry/tests/gd/cert/context.py
deleted file mode 100644
index 1e592ab5f3..0000000000
--- a/system/blueberry/tests/gd/cert/context.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2018 - 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.
-
-import enum
-import logging
-import os
-
-
-class ContextLevel(enum.IntEnum):
- ROOT = 0
- TESTCLASS = 1
- TESTCASE = 2
-
-
-def get_current_context(depth=None):
- """Get the current test context at the specified depth.
- Pulls the most recently created context, with a level at or below the given
- depth, from the _contexts stack.
-
- Args:
- depth: The desired context level. For example, the TESTCLASS level would
- yield the current test class context, even if the test is currently
- within a test case.
-
- Returns: An instance of TestContext.
- """
- if depth is None:
- return _contexts[-1]
- return _contexts[min(depth, len(_contexts) - 1)]
-
-
-def append_test_context(test_class_name, test_name):
- """Add test-specific context to the _contexts stack.
- A test should should call append_test_context() at test start and
- pop_test_context() upon test end.
-
- Args:
- test_class_name: name of the test class.
- test_name: name of the test.
- """
- if _contexts:
- _contexts.append(TestCaseContext(test_class_name, test_name))
-
-
-def pop_test_context():
- """Remove the latest test-specific context from the _contexts stack.
- A test should should call append_test_context() at test start and
- pop_test_context() upon test end.
- """
- if _contexts:
- _contexts.pop()
-
-
-class TestContext(object):
- """An object representing the current context in which a test is executing.
-
- The context encodes the current state of the test runner with respect to a
- particular scenario in which code is being executed. For example, if some
- code is being executed as part of a test case, then the context should
- encode information about that test case such as its name or enclosing
- class.
-
- The subcontext specifies a relative path in which certain outputs,
- e.g. logcat, should be kept for the given context.
-
- The full output path is given by
- <base_output_path>/<context_dir>/<subcontext>.
-
- Attributes:
- _base_output_paths: a dictionary mapping a logger's name to its base
- output path
- _subcontexts: a dictionary mapping a logger's name to its
- subcontext-level output directory
- """
-
- _base_output_paths = {}
- _subcontexts = {}
-
- def get_base_output_path(self, log_name=None):
- """Gets the base output path for this logger.
-
- The base output path is interpreted as the reporting root for the
- entire test runner.
-
- If a path has been added with add_base_output_path, it is returned.
- Otherwise, a default is determined by _get_default_base_output_path().
-
- Args:
- log_name: The name of the logger.
-
- Returns:
- The output path.
- """
- if log_name in self._base_output_paths:
- return self._base_output_paths[log_name]
- return self._get_default_base_output_path()
-
- def get_subcontext(self, log_name=None):
- """Gets the subcontext for this logger.
-
- The subcontext is interpreted as the directory, relative to the
- context-level path, where all outputs of the given logger are stored.
-
- If a path has been added with add_subcontext, it is returned.
- Otherwise, the empty string is returned.
-
- Args:
- log_name: The name of the logger.
-
- Returns:
- The output path.
- """
- return self._subcontexts.get(log_name, '')
-
- def get_full_output_path(self, log_name=None):
- """Gets the full output path for this context.
-
- The full path represents the absolute path to the output directory,
- as given by <base_output_path>/<context_dir>/<subcontext>
-
- Args:
- log_name: The name of the logger. Used to specify the base output
- path and the subcontext.
-
- Returns:
- The output path.
- """
-
- path = os.path.join(
- self.get_base_output_path(log_name), self._get_default_context_dir(), self.get_subcontext(log_name))
- os.makedirs(path, exist_ok=True)
- return path
-
- def _get_default_base_output_path(self):
- """Gets the default base output path.
-
- This will attempt to use logging path set up in the global
- logger.
-
- Returns:
- The logging path.
-
- Raises:
- EnvironmentError: If logger has not been initialized.
- """
- try:
- return logging.log_path
- except AttributeError as e:
- raise EnvironmentError('The Mobly logger has not been set up and'
- ' "base_output_path" has not been set.') from e
-
- def _get_default_context_dir(self):
- """Gets the default output directory for this context."""
- raise NotImplementedError()
-
-
-class RootContext(TestContext):
- """A TestContext that represents a test run."""
-
- @property
- def identifier(self):
- return 'root'
-
- def _get_default_context_dir(self):
- """Gets the default output directory for this context.
-
- Logs at the root level context are placed directly in the base level
- directory, so no context-level path exists."""
- return ''
-
-
-class TestCaseContext(TestContext):
- """A TestContext that represents a test case.
-
- Attributes:
- test_case: the name of the test case.
- test_class: the name of the test class.
- """
-
- def __init__(self, test_class, test_case):
- """Initializes a TestCaseContext for the given test case.
-
- Args:
- test_class: test-class name.
- test_case: test name.
- """
- self.test_class = test_class
- self.test_case = test_case
-
- @property
- def test_case_name(self):
- return self.test_case
-
- @property
- def test_class_name(self):
- return self.test_class
-
- @property
- def identifier(self):
- return '%s.%s' % (self.test_class_name, self.test_case_name)
-
- def _get_default_context_dir(self):
- """Gets the default output directory for this context.
-
- For TestCaseContexts, this will be the name of the test itself.
- """
- return self.test_case_name
-
-
-# stack for keeping track of the current test context
-_contexts = [RootContext()]
diff --git a/system/blueberry/tests/gd/cert/event_stream.py b/system/blueberry/tests/gd/cert/event_stream.py
deleted file mode 100644
index ee3db7596a..0000000000
--- a/system/blueberry/tests/gd/cert/event_stream.py
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-from abc import ABC, abstractmethod
-from concurrent.futures import ThreadPoolExecutor
-from datetime import datetime, timedelta
-import logging
-from queue import SimpleQueue, Empty
-
-from mobly import asserts
-
-from google.protobuf import text_format
-
-from grpc import RpcError
-
-from blueberry.tests.gd.cert.closable import Closable
-
-
-class IEventStream(ABC):
-
- @abstractmethod
- def get_event_queue(self):
- pass
-
-
-class FilteringEventStream(IEventStream):
-
- def __init__(self, stream, filter_fn):
- self.filter_fn = filter_fn if filter_fn else lambda x: x
- self.event_queue = SimpleQueue()
- self.stream = stream
-
- self.stream.register_callback(self.__event_callback, lambda packet: self.filter_fn(packet) is not None)
-
- def __event_callback(self, event):
- self.event_queue.put(self.filter_fn(event))
-
- def get_event_queue(self):
- return self.event_queue
-
- def unregister(self):
- self.stream.unregister(self.__event_callback)
-
-
-def pretty_print(proto_event):
- return '{} {}'.format(type(proto_event).__name__, text_format.MessageToString(proto_event, as_one_line=True))
-
-
-DEFAULT_TIMEOUT_SECONDS = 30
-
-
-class EventStream(IEventStream, Closable):
- """
- A class that streams events from a gRPC stream, which you can assert on.
-
- Don't use these asserts directly, use the ones from cert.truth.
- """
-
- def __init__(self, server_stream_call):
- if server_stream_call is None:
- raise ValueError("server_stream_call cannot be None")
-
- self.server_stream_call = server_stream_call
- self.event_queue = SimpleQueue()
- self.handlers = []
- self.executor = ThreadPoolExecutor()
- self.future = self.executor.submit(EventStream.__event_loop, self)
-
- def get_event_queue(self):
- return self.event_queue
-
- def close(self):
- """
- Stop the gRPC lambda so that event_callback will not be invoked after
- the method returns.
-
- This object will be useless after this call as there is no way to
- restart the gRPC callback. You would have to create a new EventStream
-
- :raise None on success, or the same exception as __event_loop(), or
- concurrent.futures.TimeoutError if underlying stream failed to
- terminate within DEFAULT_TIMEOUT_SECONDS
- """
- # Try to cancel the execution, don't care the result, non-blocking
- self.server_stream_call.cancel()
- try:
- # cancelling gRPC stream should cause __event_loop() to quit
- # same exception will be raised by future.result() or
- # concurrent.futures.TimeoutError will be raised after timeout
- self.future.result(timeout=DEFAULT_TIMEOUT_SECONDS)
- finally:
- # Make sure we force shutdown the executor regardless of the result
- self.executor.shutdown(wait=False)
-
- def register_callback(self, callback, matcher_fn=None):
- """
- Register a callback to handle events. Event will be handled by callback
- if matcher_fn(event) returns True
-
- callback and matcher are registered as a tuple. Hence the same callback
- with different matcher are considered two different handler units. Same
- matcher, but different callback are also considered different handling
- unit
-
- Callback will be invoked on a ThreadPoolExecutor owned by this
- EventStream
-
- :param callback: Will be called as callback(event)
- :param matcher_fn: A boolean function that returns True or False when
- calling matcher_fn(event), if None, all event will
- be matched
- """
- if callback is None:
- raise ValueError("callback must not be None")
- self.handlers.append((callback, matcher_fn))
-
- def unregister_callback(self, callback, matcher_fn=None):
- """
- Unregister callback and matcher_fn from the event stream. Both objects
- must match exactly the ones when calling register_callback()
-
- :param callback: callback used in register_callback()
- :param matcher_fn: matcher_fn used in register_callback()
- :raises ValueError when (callback, matcher_fn) tuple is not found
- """
- if callback is None:
- raise ValueError("callback must not be None")
- self.handlers.remove((callback, matcher_fn))
-
- def __event_loop(self):
- """
- Main loop for consuming the gRPC stream events.
- Blocks until computation is cancelled
- :raise grpc.Error on failure
- """
- try:
- for event in self.server_stream_call:
- self.event_queue.put(event)
- for (callback, matcher_fn) in self.handlers:
- if not matcher_fn or matcher_fn(event):
- callback(event)
- except RpcError as exp:
- # Underlying gRPC stream should run indefinitely until cancelled
- # Hence any other reason besides CANCELLED is raised as an error
- if self.server_stream_call.cancelled():
- logging.debug("Cancelled")
- else:
- raise exp
-
- def assert_event_occurs(self, match_fn, at_least_times=1, timeout=timedelta(seconds=DEFAULT_TIMEOUT_SECONDS)):
- """
- Assert at least |at_least_times| instances of events happen where
- match_fn(event) returns True within timeout period
-
- :param match_fn: returns True/False on match_fn(event)
- :param timeout: a timedelta object
- :param at_least_times: how many times at least a matching event should
- happen
- :return:
- """
- NOT_FOR_YOU_assert_event_occurs(self, match_fn, at_least_times, timeout)
-
- def assert_event_occurs_at_most(self, match_fn, at_most_times, timeout=timedelta(seconds=DEFAULT_TIMEOUT_SECONDS)):
- """
- Assert at most |at_most_times| instances of events happen where
- match_fn(event) returns True within timeout period
-
- :param match_fn: returns True/False on match_fn(event)
- :param at_most_times: how many times at most a matching event should
- happen
- :param timeout:a timedelta object
- :return:
- """
- logging.debug("assert_event_occurs_at_most")
- event_list = []
- end_time = datetime.now() + timeout
- while len(event_list) <= at_most_times and datetime.now() < end_time:
- remaining = static_remaining_time_delta(end_time)
- logging.debug("Waiting for event iteration (%fs remaining)" % (remaining.total_seconds()))
- try:
- current_event = self.event_queue.get(timeout=remaining.total_seconds())
- if match_fn(current_event):
- event_list.append(current_event)
- except Empty:
- continue
- logging.debug("Done waiting, got %d events" % len(event_list))
- assert_true(
- self,
- len(event_list) <= at_most_times,
- msg=("Expected at most %d events, but got %d" % (at_most_times, len(event_list))))
-
-
-def static_remaining_time_delta(end_time):
- remaining = end_time - datetime.now()
- if remaining < timedelta(milliseconds=0):
- remaining = timedelta(milliseconds=0)
- return remaining
-
-
-def assert_true(istream, expr, msg, extras=None):
- if not expr:
- istream.close()
- asserts.fail(msg, extras)
-
-
-def NOT_FOR_YOU_assert_event_occurs(istream,
- match_fn,
- at_least_times=1,
- timeout=timedelta(seconds=DEFAULT_TIMEOUT_SECONDS)):
- logging.debug("assert_event_occurs %d %fs" % (at_least_times, timeout.total_seconds()))
- event_list = []
- end_time = datetime.now() + timeout
- while len(event_list) < at_least_times and datetime.now() < end_time:
- remaining = static_remaining_time_delta(end_time)
- logging.debug("Waiting for event (%fs remaining)" % (remaining.total_seconds()))
- try:
- current_event = istream.get_event_queue().get(timeout=remaining.total_seconds())
- logging.debug("current_event: %s", current_event)
- if match_fn(current_event):
- event_list.append(current_event)
- except Empty:
- continue
- logging.debug("Done waiting for event, received %d", len(event_list))
-
- assert_true(
- istream,
- len(event_list) >= at_least_times,
- msg=("Expected at least %d events, but got %d" % (at_least_times, len(event_list))))
-
-
-def NOT_FOR_YOU_assert_all_events_occur(istream,
- match_fns,
- order_matters,
- timeout=timedelta(seconds=DEFAULT_TIMEOUT_SECONDS)):
- logging.debug("assert_all_events_occur %fs" % timeout.total_seconds())
- pending_matches = list(match_fns)
- matched_order = []
- end_time = datetime.now() + timeout
- while len(pending_matches) > 0 and datetime.now() < end_time:
- remaining = static_remaining_time_delta(end_time)
- logging.debug("Waiting for event (%fs remaining)" % (remaining.total_seconds()))
- try:
- current_event = istream.get_event_queue().get(timeout=remaining.total_seconds())
- for match_fn in pending_matches:
- if match_fn(current_event):
- pending_matches.remove(match_fn)
- matched_order.append(match_fn)
- except Empty:
- continue
- logging.debug("Done waiting for event")
- assert_true(
- istream,
- len(matched_order) == len(match_fns),
- msg=("Expected at least %d events, but got %d" % (len(match_fns), len(matched_order))))
- if order_matters:
- correct_order = True
- i = 0
- while i < len(match_fns):
- if match_fns[i] is not matched_order[i]:
- correct_order = False
- break
- i += 1
- assert_true(istream, correct_order, "Events not received in correct order %s %s" % (match_fns, matched_order))
-
-
-def NOT_FOR_YOU_assert_none_matching(istream, match_fn, timeout):
- logging.debug("assert_none_matching %fs" % (timeout.total_seconds()))
- event = None
- end_time = datetime.now() + timeout
- while event is None and datetime.now() < end_time:
- remaining = static_remaining_time_delta(end_time)
- logging.debug("Waiting for event (%fs remaining)" % (remaining.total_seconds()))
- try:
- current_event = istream.get_event_queue().get(timeout=remaining.total_seconds())
- if match_fn(current_event):
- event = current_event
- except Empty:
- continue
- logging.debug("Done waiting for an event")
- if event is None:
- return # Avoid an assert in MessageToString(None, ...)
- assert_true(istream, event is None, msg='Expected None matching, but got {}'.format(pretty_print(event)))
-
-
-def NOT_FOR_YOU_assert_none(istream, timeout):
- logging.debug("assert_none %fs" % (timeout.total_seconds()))
- try:
- event = istream.get_event_queue().get(timeout=timeout.total_seconds())
- assert_true(istream, event is None, msg='Expected None, but got {}'.format(pretty_print(event)))
- except Empty:
- return
diff --git a/system/blueberry/tests/gd/cert/gd_base_test.py b/system/blueberry/tests/gd/cert/gd_base_test.py
deleted file mode 100644
index c964815c8e..0000000000
--- a/system/blueberry/tests/gd/cert/gd_base_test.py
+++ /dev/null
@@ -1,305 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-import importlib
-import logging
-import os
-import traceback
-import signal
-import subprocess
-
-from blueberry.facade import rootservice_pb2 as facade_rootservice
-from functools import wraps
-from grpc import RpcError
-
-from blueberry.tests.gd.cert.async_subprocess_logger import AsyncSubprocessLogger
-from blueberry.tests.gd.cert.context import append_test_context, get_current_context, pop_test_context, ContextLevel
-from blueberry.tests.gd.cert.gd_device import MOBLY_CONTROLLER_CONFIG_NAME as CONTROLLER_CONFIG_NAME
-from blueberry.tests.gd.cert.os_utils import get_gd_root
-from blueberry.tests.gd.cert.os_utils import read_crash_snippet_and_log_tail
-from blueberry.tests.gd.cert.os_utils import is_subprocess_alive
-from blueberry.tests.gd.cert.os_utils import make_ports_available
-from blueberry.tests.gd.cert.os_utils import TerminalColor
-from blueberry.tests.gd.cert.tracelogger import TraceLogger
-
-from mobly import asserts, signals
-from mobly import base_test
-
-
-class Timeout:
-
- def __init__(self, seconds=1, error_message='Timeout'):
- self.seconds = seconds
- self.error_message = error_message
-
- def handle_timeout(self, signum, frame):
- raise TimeoutError(self.error_message)
-
- def __enter__(self):
- signal.signal(signal.SIGALRM, self.handle_timeout)
- signal.alarm(self.seconds)
-
- def __exit__(self, type, value, traceback):
- signal.alarm(0)
-
-
-class GdBaseTestClass(base_test.BaseTestClass):
-
- FUNCTION_CALL_TIMEOUT_SECONDS = 5
- SUBPROCESS_WAIT_TIMEOUT_SECONDS = 10
-
- def setup_class(self, dut_module, cert_module):
- self.dut_module = dut_module
- self.cert_module = cert_module
- self.log = TraceLogger(logging.getLogger())
- self.dut_coverage_info = None
- self.cert_coverage_info = None
-
- def teardown_class(self):
- # assume each test runs the same binary for dut and cert
- # generate coverage report after running all tests in a class
- if self.dut_coverage_info:
- self.dut.generate_coverage_report_for_host(self.dut_coverage_info)
- self.dut_coverage_info = None
- if self.cert_coverage_info:
- self.cert.generate_coverage_report_for_host(self.cert_coverage_info)
- self.cert_coverage_info = None
-
- def set_controller_properties_path(self, path):
- GD_DIR = os.path.join(os.getcwd(), os.pardir)
- self.controller_properties_file = os.path.join(GD_DIR, path)
-
- def setup_test(self):
- append_test_context(test_class_name=self.TAG, test_name=self.current_test_info.name)
- self.log_path_base = get_current_context().get_full_output_path()
- self.verbose_mode = bool(self.user_params.get('verbose_mode', False))
- for config in self.controller_configs[CONTROLLER_CONFIG_NAME]:
- config['verbose_mode'] = self.verbose_mode
-
- try:
- controller_properties_file = self.controller_properties_file
- except AttributeError:
- controller_properties_file = ''
-
- self.setup_rootcanal(controller_properties_file)
-
- # Parse and construct GD device objects
- self.register_controller(importlib.import_module('blueberry.tests.gd.cert.gd_device'), builtin=True)
- self.dut = self.gd_device[1]
- self.cert = self.gd_device[0]
- if self.dut.host_only_device:
- new_dut_coverage_info = self.dut.get_coverage_info()
- if self.dut_coverage_info:
- asserts.assert_true(self.dut_coverage_info == new_dut_coverage_info,
- msg="DUT coverage info must be the same for each test run, old: {}, new: {}".format(
- self.dut_coverage_info, new_dut_coverage_info))
- self.dut_coverage_info = new_dut_coverage_info
- if self.cert.host_only_device:
- new_cert_coverage_info = self.cert.get_coverage_info()
- if self.cert_coverage_info:
- asserts.assert_true(
- self.cert_coverage_info == new_cert_coverage_info,
- msg="CERT coverage info must be the same for each test run, old: {}, new: {}".format(
- self.cert_coverage_info, new_cert_coverage_info))
- self.cert_coverage_info = new_cert_coverage_info
-
- try:
- self.dut.rootservice.StartStack(
- facade_rootservice.StartStackRequest(
- module_under_test=facade_rootservice.BluetoothModule.Value(self.dut_module)))
- except RpcError as rpc_error:
- asserts.fail("Failed to start DUT stack, RpcError={!r}".format(rpc_error))
- try:
- self.cert.rootservice.StartStack(
- facade_rootservice.StartStackRequest(
- module_under_test=facade_rootservice.BluetoothModule.Value(self.cert_module)))
- except RpcError as rpc_error:
- asserts.fail("Failed to start CERT stack, RpcError={!r}".format(rpc_error))
- self.dut.wait_channel_ready()
- self.cert.wait_channel_ready()
-
- def teardown_test(self):
- stack = ""
- try:
- with Timeout(seconds=self.FUNCTION_CALL_TIMEOUT_SECONDS):
- stack = "CERT"
- self.cert.rootservice.StopStack(facade_rootservice.StopStackRequest())
- stack = "DUT"
- self.dut.rootservice.StopStack(facade_rootservice.StopStackRequest())
- except RpcError as rpc_error:
- asserts.fail("Failed to stop {} stack, RpcError={!r}".format(stack, rpc_error))
- except TimeoutError:
- logging.error("Failed to stop {} stack in {} s".format(stack, self.FUNCTION_CALL_TIMEOUT_SECONDS))
- finally:
- # Destroy GD device objects
- self._controller_manager.unregister_controllers()
- self.teardown_rootcanal()
- pop_test_context()
-
- def setup_rootcanal(self, controller_properties_file=''):
- # Start root-canal if needed
- self.rootcanal_running = False
- self.rootcanal_logpath = None
- self.rootcanal_process = None
- self.rootcanal_logger = None
- if 'rootcanal' in self.controller_configs:
- self.rootcanal_running = True
- # Get root canal binary
- rootcanal = os.path.join(get_gd_root(), "root-canal")
- asserts.assert_true(os.path.isfile(rootcanal), "Root canal does not exist at %s" % rootcanal)
-
- # Get root canal log
- self.rootcanal_logpath = os.path.join(self.log_path_base, 'rootcanal_logs.txt')
- # Make sure ports are available
- rootcanal_config = self.controller_configs['rootcanal']
- rootcanal_test_port = int(rootcanal_config.get("test_port", "6401"))
- rootcanal_hci_port = int(rootcanal_config.get("hci_port", "6402"))
- rootcanal_link_layer_port = int(rootcanal_config.get("link_layer_port", "6403"))
- asserts.assert_true(
- make_ports_available((rootcanal_test_port, rootcanal_hci_port, rootcanal_link_layer_port)),
- "Failed to free ports rootcanal_test_port={}, rootcanal_hci_port={}, rootcanal_link_layer_port={}".
- format(rootcanal_test_port, rootcanal_hci_port, rootcanal_link_layer_port))
-
- # Start root canal process
- rootcanal_cmd = [
- rootcanal, '-test_port',
- str(rootcanal_test_port), '-hci_port',
- str(rootcanal_hci_port), '-link_port',
- str(rootcanal_link_layer_port), '-controller_properties_file=' + controller_properties_file
- ]
- self.log.debug("Running %s" % " ".join(rootcanal_cmd))
- self.rootcanal_process = subprocess.Popen(rootcanal_cmd,
- cwd=get_gd_root(),
- env=os.environ.copy(),
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
-
- asserts.assert_true(self.rootcanal_process, msg="Cannot start root-canal at " + str(rootcanal))
- asserts.assert_true(is_subprocess_alive(self.rootcanal_process),
- msg="root-canal stopped immediately after running")
-
- self.rootcanal_logger = AsyncSubprocessLogger(self.rootcanal_process, [self.rootcanal_logpath],
- log_to_stdout=self.verbose_mode,
- tag="rootcanal",
- color=TerminalColor.MAGENTA)
-
- # Modify the device config to include the correct root-canal port
- for gd_device_config in self.controller_configs.get("GdDevice"):
- gd_device_config["rootcanal_port"] = str(rootcanal_hci_port)
-
- def teardown_rootcanal(self):
- if self.rootcanal_running:
- stop_signal = signal.SIGINT
- self.rootcanal_process.send_signal(stop_signal)
- try:
- return_code = self.rootcanal_process.wait(timeout=self.SUBPROCESS_WAIT_TIMEOUT_SECONDS)
- except subprocess.TimeoutExpired:
- logging.error("Failed to interrupt root canal via SIGINT, sending SIGKILL")
- stop_signal = signal.SIGKILL
- self.rootcanal_process.kill()
- try:
- return_code = self.rootcanal_process.wait(timeout=self.SUBPROCESS_WAIT_TIMEOUT_SECONDS)
- except subprocess.TimeoutExpired:
- logging.error("Failed to kill root canal")
- return_code = -65536
- if return_code != 0 and return_code != -stop_signal:
- logging.error("rootcanal stopped with code: %d" % return_code)
- self.rootcanal_logger.stop()
-
- @staticmethod
- def get_module_reference_name(a_module):
- """Returns the module's module's submodule name as reference name.
-
- Args:
- a_module: Any module. Ideally, a controller module.
- Returns:
- A string corresponding to the module's name.
- """
- return a_module.__name__.split('.')[-1]
-
- def register_controller(self, controller_module, required=True, builtin=False):
- """Registers an controller module for a test class. Invokes Mobly's
- implementation of register_controller.
- """
- module_ref_name = self.get_module_reference_name(controller_module)
- module_config_name = controller_module.MOBLY_CONTROLLER_CONFIG_NAME
-
- # Get controller objects from Mobly's register_controller
- controllers = self._controller_manager.register_controller(controller_module, required=required)
- if not controllers:
- return None
-
- # Log controller information
- # Implementation of "get_info" is optional for a controller module.
- if hasattr(controller_module, "get_info"):
- controller_info = controller_module.get_info(controllers)
- self.log.info("Controller %s: %s", module_config_name, controller_info)
-
- if builtin:
- setattr(self, module_ref_name, controllers)
- return controllers
-
- def __getattribute__(self, name):
- attr = super().__getattribute__(name)
- if not callable(attr) or not GdBaseTestClass.__is_entry_function(name):
- return attr
-
- @wraps(attr)
- def __wrapped(*args, **kwargs):
- try:
- return attr(*args, **kwargs)
- except RpcError as e:
- exception_info = "".join(traceback.format_exception(e.__class__, e, e.__traceback__))
- raise signals.TestFailure("RpcError during test\n\nRpcError:\n\n%s\n%s" %
- (exception_info, self.__dump_crashes()))
-
- return __wrapped
-
- __ENTRY_METHODS = {"setup_class", "teardown_class", "setup_test", "teardown_test"}
-
- @staticmethod
- def __is_entry_function(name):
- return name.startswith("test_") or name in GdBaseTestClass.__ENTRY_METHODS
-
- def __dump_crashes(self):
- """
- return: formatted stack traces if found, or last few lines of log
- """
- dut_crash, dut_log_tail = self.dut.get_crash_snippet_and_log_tail()
- cert_crash, cert_log_tail = self.cert.get_crash_snippet_and_log_tail()
- rootcanal_crash = None
- rootcanal_log_tail = None
- if self.rootcanal_running and not is_subprocess_alive(self.rootcanal_process):
- rootcanal_crash, roocanal_log_tail = read_crash_snippet_and_log_tail(self.rootcanal_logpath)
-
- crash_detail = ""
- if dut_crash or cert_crash or rootcanal_crash:
- if rootcanal_crash:
- crash_detail += "rootcanal crashed:\n\n%s\n\n" % rootcanal_crash
- if dut_crash:
- crash_detail += "dut stack crashed:\n\n%s\n\n" % dut_crash
- if cert_crash:
- crash_detail += "cert stack crashed:\n\n%s\n\n" % cert_crash
- else:
- if rootcanal_log_tail:
- crash_detail += "rootcanal log tail:\n\n%s\n\n" % rootcanal_log_tail
- if dut_log_tail:
- crash_detail += "dut log tail:\n\n%s\n\n" % dut_log_tail
- if cert_log_tail:
- crash_detail += "cert log tail:\n\n%s\n\n" % cert_log_tail
-
- return crash_detail
diff --git a/system/blueberry/tests/gd/cert/gd_device.py b/system/blueberry/tests/gd/cert/gd_device.py
deleted file mode 100644
index 99077d470f..0000000000
--- a/system/blueberry/tests/gd/cert/gd_device.py
+++ /dev/null
@@ -1,866 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-from abc import ABC
-from abc import abstractmethod
-from datetime import datetime
-import inspect
-import logging
-import os
-import pathlib
-import shutil
-import signal
-import subprocess
-import time
-from typing import List
-
-import grpc
-
-from google.protobuf import empty_pb2 as empty_proto
-
-from blueberry.tests.gd.cert import asserts
-from blueberry.tests.gd.cert.adb import BlueberryAdbProxy
-from blueberry.tests.gd.cert.adb import UTF_8
-from blueberry.tests.gd.cert.async_subprocess_logger import AsyncSubprocessLogger
-from blueberry.tests.gd.cert.context import get_current_context
-from blueberry.tests.gd.cert.logging_client_interceptor import LoggingClientInterceptor
-from blueberry.tests.gd.cert.os_utils import get_gd_root
-from blueberry.tests.gd.cert.os_utils import read_crash_snippet_and_log_tail
-from blueberry.tests.gd.cert.os_utils import is_subprocess_alive
-from blueberry.tests.gd.cert.os_utils import make_ports_available
-from blueberry.tests.gd.cert.os_utils import TerminalColor
-
-from blueberry.facade import rootservice_pb2_grpc as facade_rootservice_pb2_grpc
-from blueberry.facade.hal import hal_facade_pb2_grpc
-from blueberry.facade.hci import hci_facade_pb2_grpc
-from blueberry.facade.hci import acl_manager_facade_pb2_grpc
-from blueberry.facade.hci import controller_facade_pb2_grpc
-from blueberry.facade.hci import le_acl_manager_facade_pb2_grpc
-from blueberry.facade.hci import le_advertising_manager_facade_pb2_grpc
-from blueberry.facade.hci import le_initiator_address_facade_pb2_grpc
-from blueberry.facade.hci import le_scanning_manager_facade_pb2_grpc
-from blueberry.facade.l2cap.classic import facade_pb2_grpc as l2cap_facade_pb2_grpc
-from blueberry.facade.l2cap.le import facade_pb2_grpc as l2cap_le_facade_pb2_grpc
-from blueberry.facade.neighbor import facade_pb2_grpc as neighbor_facade_pb2_grpc
-
-from mobly import utils
-from mobly.controllers.android_device_lib.adb import AdbError
-
-ADB_FILE_NOT_EXIST_ERROR = "No such file or directory"
-GRPC_START_TIMEOUT_SEC = 15
-MOBLY_CONTROLLER_CONFIG_NAME = "GdDevice"
-PORT_FORWARDING_ERROR_MSG_PREFIX = "During port forwarding cleanup: "
-PULL_LOG_FILE_ERROR_MSG_PREFIX = "While trying to pull log files"
-
-
-def create(configs):
- if not configs:
- raise Exception("Configuration is empty")
- elif not isinstance(configs, list):
- raise Exception("Configuration should be a list")
- return get_instances_with_configs(configs)
-
-
-def destroy(devices):
- for device in devices:
- try:
- device.teardown()
- except:
- logging.exception("[%s] Failed to clean up properly due to" % device.label)
-
-
-def get_info(devices):
- return []
-
-
-def replace_vars(string, config):
- serial_number = config.get("serial_number")
- if serial_number is None:
- serial_number = ""
- rootcanal_port = config.get("rootcanal_port")
- if rootcanal_port is None:
- rootcanal_port = ""
- if serial_number == "DUT" or serial_number == "CERT":
- raise Exception("Did you forget to configure the serial number?")
- return string.replace("$GD_ROOT", get_gd_root()) \
- .replace("$(grpc_port)", config.get("grpc_port")) \
- .replace("$(grpc_root_server_port)", config.get("grpc_root_server_port")) \
- .replace("$(rootcanal_port)", rootcanal_port) \
- .replace("$(signal_port)", config.get("signal_port")) \
- .replace("$(serial_number)", serial_number)
-
-
-def get_instances_with_configs(configs):
- print(configs)
- devices = []
- for config in configs:
- resolved_cmd = []
- for arg in config["cmd"]:
- logging.debug(arg)
- resolved_cmd.append(replace_vars(arg, config))
- verbose_mode = bool(config.get('verbose_mode', False))
- if config.get("serial_number"):
- device = GdAndroidDevice(config["grpc_port"], config["grpc_root_server_port"], config["signal_port"],
- resolved_cmd, config["label"], MOBLY_CONTROLLER_CONFIG_NAME, config["name"],
- config["serial_number"], verbose_mode)
- else:
- device = GdHostOnlyDevice(config["grpc_port"], config["grpc_root_server_port"], config["signal_port"],
- resolved_cmd, config["label"], MOBLY_CONTROLLER_CONFIG_NAME, config["name"],
- verbose_mode)
- device.setup()
- devices.append(device)
- return devices
-
-
-class GdDeviceBase(ABC):
- """
- Base GD device class that covers common traits which assumes that the
- device must be driven by a driver-like backing process that takes following
- command line arguments:
- --grpc-port: main entry port for facade services
- --root-server-port: management port for starting and stopping services
- --btsnoop: path to btsnoop HCI log
- --signal-port: signaling port to indicate that backing process is started
- --rootcanal-port: root-canal HCI port, optional
- """
-
- WAIT_CHANNEL_READY_TIMEOUT_SECONDS = 10
- WAIT_SIGINT_TIMEOUT_SECONDS = 5
- WAIT_SIGKILL_TIMEOUT_SECONDS = 1
-
- def __init__(self, grpc_port: str, grpc_root_server_port: str, signal_port: str, cmd: List[str], label: str,
- type_identifier: str, name: str, verbose_mode: bool):
- """Verify arguments and log path, initialize Base GD device, common traits
- for both device based and host only GD cert tests
- :param grpc_port: main gRPC service port
- :param grpc_root_server_port: gRPC root server port
- :param signal_port: signaling port for backing process start up
- :param cmd: list of arguments to run in backing process
- :param label: device label used in logs
- :param type_identifier: device type identifier used in logs
- :param name: name of device used in logs
- """
- # Must be at the first line of __init__ method
- values = locals()
- arguments = [values[arg] for arg in inspect.getfullargspec(GdDeviceBase.__init__).args if arg != "verbose_mode"]
- asserts.assert_true(all(arguments), "All arguments to GdDeviceBase must not be None nor empty")
- asserts.assert_true(all(cmd), "cmd list should not have None nor empty component")
- self.verbose_mode = verbose_mode
- self.host_only_device = False
- self.grpc_root_server_port = int(grpc_root_server_port)
- self.grpc_port = int(grpc_port)
- self.signal_port = int(signal_port)
- self.name = name
- self.type_identifier = type_identifier
- self.label = label
- self.log_path_base = get_current_context().get_full_output_path()
- self.test_runner_base_path = \
- get_current_context().get_base_output_path()
- self.backing_process_log_path = os.path.join(self.log_path_base,
- '%s_%s_backing_logs.txt' % (self.type_identifier, self.label))
- if "--btsnoop=" not in " ".join(cmd):
- cmd.append("--btsnoop=%s" % os.path.join(self.log_path_base, '%s_btsnoop_hci.log' % self.label))
- if "--btsnooz=" not in " ".join(cmd):
- cmd.append("--btsnooz=%s" % os.path.join(self.log_path_base, '%s_btsnooz_hci.log' % self.label))
- if "--btconfig=" not in " ".join(cmd):
- cmd.append("--btconfig=%s" % os.path.join(self.log_path_base, '%s_bt_config.conf' % self.label))
- self.cmd = cmd
- self.environment = os.environ.copy()
- if "cert" in self.label:
- self.terminal_color = TerminalColor.BLUE
- else:
- self.terminal_color = TerminalColor.YELLOW
-
- def setup(self):
- """Set up this device for test, ensure signal port is available and backing process is started and alive,
- must run before using this device.
- - After calling this, teardown() must be called when test finishes
- - Should be executed after children classes' setup() methods
- :return:
- """
- # Start backing process
- logging.debug("[%s] Running %s %s" % (self.type_identifier, self.label, " ".join(self.cmd)))
- self.backing_process = subprocess.Popen(self.cmd,
- cwd=get_gd_root(),
- env=self.environment,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
-
- self.backing_process_logger = AsyncSubprocessLogger(self.backing_process, [self.backing_process_log_path],
- log_to_stdout=self.verbose_mode,
- tag=self.label,
- color=self.terminal_color)
-
- asserts.assert_true(self.backing_process,
- msg="[%s] failed to open backing process for %s" % (self.type_identifier, self.label))
- self.is_backing_process_alive = is_subprocess_alive(self.backing_process)
-
- asserts.assert_true(self.is_backing_process_alive,
- msg="[%s] backing process for %s died after starting" % (self.type_identifier, self.label))
-
- # If gRPC root server port is not specified, we can skip settings up the root server
- if self.grpc_root_server_port != -1:
- # Setup gRPC management channels
- self.grpc_root_server_channel = grpc.insecure_channel("localhost:%d" % self.grpc_root_server_port)
-
- self.grpc_root_server_ready = False
-
- try:
- logging.info("[%s] Waiting to connect to gRPC root server for %s, timeout is %d seconds" %
- (self.type_identifier, self.label, GRPC_START_TIMEOUT_SEC))
- grpc.channel_ready_future(self.grpc_root_server_channel).result(timeout=GRPC_START_TIMEOUT_SEC)
- logging.info("[%s] Successfully connected to gRPC root server for %s" %
- (self.type_identifier, self.label))
- self.grpc_root_server_ready = True
- except grpc.FutureTimeoutError:
- logging.error("[%s] Failed to connect to gRPC root server for %s" % (self.type_identifier, self.label))
-
- asserts.assert_true(self.grpc_root_server_ready,
- msg="gRPC root server did not start after running " + " ".join(self.cmd))
-
- self.grpc_channel = grpc.insecure_channel("localhost:%d" % self.grpc_port)
-
- if self.verbose_mode:
- self.grpc_channel = grpc.intercept_channel(self.grpc_channel, LoggingClientInterceptor(self.label))
-
- # Establish services from facades
- if self.grpc_root_server_port != -1:
- self.rootservice = facade_rootservice_pb2_grpc.RootFacadeStub(self.grpc_root_server_channel)
-
- self.hal = hal_facade_pb2_grpc.HciHalFacadeStub(self.grpc_channel)
- self.controller_read_only_property = facade_rootservice_pb2_grpc.ReadOnlyPropertyStub(self.grpc_channel)
- self.hci = hci_facade_pb2_grpc.HciFacadeStub(self.grpc_channel)
- self.l2cap = l2cap_facade_pb2_grpc.L2capClassicModuleFacadeStub(self.grpc_channel)
- self.l2cap_le = l2cap_le_facade_pb2_grpc.L2capLeModuleFacadeStub(self.grpc_channel)
- self.hci_acl_manager = acl_manager_facade_pb2_grpc.AclManagerFacadeStub(self.grpc_channel)
- self.hci_le_acl_manager = le_acl_manager_facade_pb2_grpc.LeAclManagerFacadeStub(self.grpc_channel)
- self.hci_le_initiator_address = le_initiator_address_facade_pb2_grpc.LeInitiatorAddressFacadeStub(
- self.grpc_channel)
- self.hci_controller = controller_facade_pb2_grpc.ControllerFacadeStub(self.grpc_channel)
- self.hci_controller.GetMacAddressSimple = lambda: self.hci_controller.GetMacAddress(empty_proto.Empty()).address
- self.hci_controller.GetLocalNameSimple = lambda: self.hci_controller.GetLocalName(empty_proto.Empty()).name
- self.hci_le_advertising_manager = le_advertising_manager_facade_pb2_grpc.LeAdvertisingManagerFacadeStub(
- self.grpc_channel)
- self.hci_le_scanning_manager = le_scanning_manager_facade_pb2_grpc.LeScanningManagerFacadeStub(
- self.grpc_channel)
- self.neighbor = neighbor_facade_pb2_grpc.NeighborFacadeStub(self.grpc_channel)
-
- def get_crash_snippet_and_log_tail(self):
- if is_subprocess_alive(self.backing_process):
- return None, None
-
- return read_crash_snippet_and_log_tail(self.backing_process_log_path)
-
- def teardown(self):
- """Tear down this device and clean up any resources.
- - Must be called after setup()
- - Should be executed before children classes' teardown()
- :return:
- """
- self.grpc_channel.close()
- if self.grpc_root_server_port != -1:
- self.grpc_root_server_channel.close()
- stop_signal = self.gracefully_stop_backing_process()
- try:
- if stop_signal == 0:
- raise RuntimeError("Failed to gracefully shutdown backing process")
- return_code = self.backing_process.wait(timeout=self.WAIT_SIGINT_TIMEOUT_SECONDS)
- except (subprocess.TimeoutExpired, RuntimeError):
- logging.error("[%s] Failed to interrupt backing process via SIGINT, sending SIGKILL" % self.label)
- stop_signal = signal.SIGKILL
- self.backing_process.kill()
- try:
- return_code = self.backing_process.wait(timeout=self.WAIT_SIGKILL_TIMEOUT_SECONDS)
- except subprocess.TimeoutExpired:
- logging.error("Failed to kill backing process")
- return_code = -65536
- if return_code not in [-stop_signal, 0]:
- logging.error("backing process %s stopped with code: %d" % (self.label, return_code))
- self.backing_process_logger.stop()
-
- def wait_channel_ready(self):
- future = grpc.channel_ready_future(self.grpc_channel)
- try:
- future.result(timeout=self.WAIT_CHANNEL_READY_TIMEOUT_SECONDS)
- except grpc.FutureTimeoutError:
- asserts.fail("[%s] wait channel ready timeout" % self.label)
-
- @abstractmethod
- def gracefully_stop_backing_process(self):
- return NotImplemented
-
-
-class GdHostOnlyDevice(GdDeviceBase):
- """
- Host only device where the backing process is running on the host machine
- """
-
- def __init__(self, grpc_port: str, grpc_root_server_port: str, signal_port: str, cmd: List[str], label: str,
- type_identifier: str, name: str, verbose_mode: bool):
- super().__init__(grpc_port, grpc_root_server_port, signal_port, cmd, label, MOBLY_CONTROLLER_CONFIG_NAME, name,
- verbose_mode)
- self.host_only_device = True
- # Enable LLVM code coverage output for host only tests
- self.backing_process_profraw_path = pathlib.Path(self.log_path_base).joinpath(
- "%s_%s_backing_coverage.profraw" % (self.type_identifier, self.label))
- self.environment["LLVM_PROFILE_FILE"] = str(self.backing_process_profraw_path)
- llvm_binutils = pathlib.Path(get_gd_root()).joinpath("llvm_binutils").joinpath("bin")
- llvm_symbolizer = llvm_binutils.joinpath("llvm-symbolizer")
- if llvm_symbolizer.is_file():
- self.environment["ASAN_SYMBOLIZER_PATH"] = llvm_symbolizer
- else:
- logging.warning("[%s] Cannot find LLVM symbolizer at %s" % (self.label, str(llvm_symbolizer)))
- self.profdata_path = self.get_coverage_profdata_path_for_host(self.test_runner_base_path, self.type_identifier,
- self.label)
-
- def setup(self):
- # Ensure ports are available
- # Only check on host only test, for Android devices, these ports will
- # be opened on Android device and host machine ports will be occupied
- # by sshd or adb forwarding
- ports_needed = [self.grpc_port, self.grpc_root_server_port
- ] if self.grpc_root_server_port != -1 else [self.grpc_port]
- asserts.assert_true(make_ports_available(ports_needed),
- "[%s] Failed to make backing process ports available" % self.label)
- super().setup()
-
- def teardown(self):
- super().teardown()
- self.merge_coverage_profdata_for_host(self.backing_process_profraw_path, self.profdata_path, self.label)
-
- def get_coverage_info(self):
- """
- Get information needed for coverage reporting
- :return: a dictionary with all information needed for coverage reporting
- """
- return {
- "profdata_path": self.profdata_path,
- "label": self.label,
- "test_runner_base_path": self.test_runner_base_path,
- "type_identifier": self.type_identifier,
- "stack_bin": self.cmd[0]
- }
-
- def get_coverage_profdata_path_for_host(self, test_runner_base_path, type_identifier, label) -> pathlib.Path:
- return pathlib.Path(test_runner_base_path).parent.parent.joinpath("%s_%s_backing_process_coverage.profdata" %
- (type_identifier, label))
-
- def merge_coverage_profdata_for_host(self, backing_process_profraw_path, profdata_path: pathlib.Path, label):
- if not backing_process_profraw_path.is_file():
- logging.info("[%s] Skip coverage report as there is no profraw file at %s" %
- (label, str(backing_process_profraw_path)))
- return
- try:
- if backing_process_profraw_path.stat().st_size <= 0:
- logging.info("[%s] Skip coverage report as profraw file is empty at %s" %
- (label, str(backing_process_profraw_path)))
- return
- except OSError:
- logging.info("[%s] Skip coverage report as profraw file is inaccessible at %s" %
- (label, str(backing_process_profraw_path)))
- return
- llvm_binutils = pathlib.Path(get_gd_root()).joinpath("llvm_binutils").joinpath("bin")
- llvm_profdata = llvm_binutils.joinpath("llvm-profdata")
- if not llvm_profdata.is_file():
- logging.info("[%s] Skip coverage report as llvm-profdata is not found at %s" % (label, str(llvm_profdata)))
- return
- logging.info("[%s] Merging coverage profdata" % label)
- profdata_path_tmp = profdata_path.parent / (profdata_path.stem + "_tmp" + profdata_path.suffix)
- # Merge with existing profdata if possible
- profdata_cmd = [str(llvm_profdata), "merge", "-sparse", str(backing_process_profraw_path)]
- if profdata_path.is_file():
- profdata_cmd.append(str(profdata_path))
- profdata_cmd += ["-o", str(profdata_path_tmp)]
- logging.debug("Running llvm_profdata: %s" % " ".join(profdata_cmd))
- result = subprocess.run(profdata_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- if result.returncode != 0:
- logging.warning("[%s] Failed to index profdata, cmd result: %r" % (label, result))
- profdata_path.unlink(missing_ok=True)
- return
- shutil.move(profdata_path_tmp, profdata_path)
-
- def generate_coverage_report_for_host(self, coverage_info):
- label = coverage_info["label"]
- test_runner_base_path = coverage_info["test_runner_base_path"]
- type_identifier = coverage_info["type_identifier"]
- profdata_path = coverage_info["profdata_path"]
- stack_bin = coverage_info["stack_bin"]
- llvm_binutils = pathlib.Path(get_gd_root()).joinpath("llvm_binutils").joinpath("bin")
- llvm_cov = llvm_binutils.joinpath("llvm-cov")
- if not llvm_cov.is_file():
- logging.info("[%s] Skip coverage report as llvm-cov is not found at %s" % (label, str(llvm_cov)))
- return
- logging.info("[%s] Generating coverage report in JSON" % label)
- coverage_result_path = pathlib.Path(test_runner_base_path).parent.parent.joinpath(
- "%s_%s_backing_process_coverage.json" % (type_identifier, label))
- with coverage_result_path.open("w") as coverage_result_file:
- llvm_cov_export_cmd = [
- str(llvm_cov), "export", "--format=text", "--ignore-filename-regex", "(external|out).*",
- "--instr-profile",
- str(profdata_path),
- str(stack_bin)
- ]
- logging.debug("Running llvm_cov export: %s" % " ".join(llvm_cov_export_cmd))
- result = subprocess.run(llvm_cov_export_cmd,
- stderr=subprocess.PIPE,
- stdout=coverage_result_file,
- cwd=os.path.join(get_gd_root()))
- if result.returncode != 0:
- logging.warning("[%s] Failed to generated coverage report, cmd result: %r" % (label, result))
- coverage_result_path.unlink(missing_ok=True)
- return
- logging.info("[%s] Generating coverage summary in text" % label)
- coverage_summary_path = pathlib.Path(test_runner_base_path).parent.parent.joinpath(
- "%s_%s_backing_process_coverage_summary.txt" % (type_identifier, label))
- with coverage_summary_path.open("w") as coverage_summary_file:
- llvm_cov_report_cmd = [
- str(llvm_cov), "report", "--ignore-filename-regex", "(external|out).*", "--instr-profile",
- str(profdata_path),
- str(stack_bin)
- ]
- logging.debug("Running llvm_cov report: %s" % " ".join(llvm_cov_report_cmd))
- result = subprocess.run(llvm_cov_report_cmd,
- stderr=subprocess.PIPE,
- stdout=coverage_summary_file,
- cwd=os.path.join(get_gd_root()))
- if result.returncode != 0:
- logging.warning("[%s] Failed to generated coverage summary, cmd result: %r" % (label, result))
- coverage_summary_path.unlink(missing_ok=True)
-
- def gracefully_stop_backing_process(self):
- stop_signal = signal.SIGINT
- self.backing_process.send_signal(stop_signal)
- return stop_signal
-
-
-class GdAndroidDevice(GdDeviceBase):
- """Real Android device where the backing process is running on it
- """
-
- WAIT_FOR_DEVICE_TIMEOUT_SECONDS = 180
- WAIT_FOR_DEVICE_SIGINT_TIMEOUT_SECONDS = 1
- ADB_ABORT_EXIT_CODE = 134
- DEVICE_LIB_DIR = "/system/lib64"
- DEVICE_BIN_DIR = "/system/bin"
-
- def __init__(self, grpc_port: str, grpc_root_server_port: str, signal_port: str, cmd: List[str], label: str,
- type_identifier: str, name: str, serial_number: str, verbose_mode: bool):
- super().__init__(grpc_port, grpc_root_server_port, signal_port, cmd, label, type_identifier, name, verbose_mode)
- asserts.assert_true(serial_number, "serial_number must not be None nor empty")
- self.serial_number = serial_number
- self.adb = BlueberryAdbProxy(serial_number)
-
- def setup(self):
- logging.info("Setting up device %s %s" % (self.label, self.serial_number))
- asserts.assert_true(self.adb.ensure_root(), "device %s cannot run as root", self.serial_number)
- self.ensure_verity_disabled()
- logging.info("Confirmed that verity is disabled on device %s %s" % (self.label, self.serial_number))
-
- # Try freeing ports and ignore results
- asserts.assert_true(make_ports_available((self.grpc_port, self.grpc_root_server_port, self.signal_port)),
- "[%s] Failed to make backing process ports available" % self.label)
- self.cleanup_port_forwarding()
- self.sync_device_time()
- logging.info("Ports cleaned up and clock is set for device %s %s" % (self.label, self.serial_number))
-
- # Set up port forwarding or reverse or die
- self.tcp_forward_or_die(self.grpc_port, self.grpc_port)
- if self.grpc_root_server_port != -1:
- self.tcp_forward_or_die(self.grpc_root_server_port, self.grpc_root_server_port)
- self.tcp_reverse_or_die(self.signal_port, self.signal_port)
- logging.info("Port forwarding done on device %s %s" % (self.label, self.serial_number))
-
- # Push test binaries
- local_dir = os.path.join(get_gd_root(), "target")
-
- def generate_dir_pair(local_dir, device_dir, filename):
- return os.path.join(local_dir, filename), os.path.join(device_dir, filename)
-
- # Do not override exist libraries shared by other binaries on the Android device to avoid corrupting the Android device
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_BIN_DIR, "bluetooth_stack_with_facade"))
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "android.hardware.bluetooth@1.0.so"),
- overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "android.hardware.bluetooth@1.1.so"),
- overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libandroid_runtime_lazy.so"),
- overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libbase.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libbinder_ndk.so"),
- overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libbinder.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libc++.so"), overwrite_existing=False)
- # libclang_rt.asan-aarch64-android.so is only needed for ASAN build and is automatically included on device
- #self.push_or_die(
- # *generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libclang_rt.asan-aarch64-android.so"),
- # overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libcrypto.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libcutils.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc_wrap.so"),
- overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc++.so"))
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libhidlbase.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "liblog.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "liblzma.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libprotobuf-cpp-full.so"))
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libssl.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc++.so"))
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libunwindstack.so"),
- overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libutils.so"), overwrite_existing=False)
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libgrpc++.so"))
- self.push_or_die(*generate_dir_pair(local_dir, self.DEVICE_LIB_DIR, "libz.so"), overwrite_existing=False)
-
- logging.info("Binaries pushed to device %s %s" % (self.label, self.serial_number))
-
- try:
- self.adb.shell("rm /data/misc/bluetooth/logs/btsnoop_hci.log")
- except AdbError as error:
- if ADB_FILE_NOT_EXIST_ERROR not in str(error):
- logging.error("Error during setup: " + str(error))
-
- try:
- self.adb.shell("rm /data/misc/bluetooth/logs/btsnooz_hci.log")
- except AdbError as error:
- if ADB_FILE_NOT_EXIST_ERROR not in str(error):
- logging.error("Error during setup: " + str(error))
-
- try:
- self.adb.shell("rm /data/misc/bluedroid/bt_config.conf")
- except AdbError as error:
- if ADB_FILE_NOT_EXIST_ERROR not in str(error):
- logging.error("Error during setup: " + str(error))
-
- logging.info("Old logs removed from device %s %s" % (self.label, self.serial_number))
-
- # Ensure Bluetooth is disabled
- self.ensure_no_output(self.adb.shell("settings put global ble_scan_always_enabled 0"))
- self.adb.shell("cmd bluetooth_manager disable")
- device_bt_state = int(self.adb.shell("settings get global bluetooth_on"))
- asserts.assert_equal(device_bt_state, 0,
- "Failed to disable Bluetooth on device %s %s" % (self.label, self.serial_number))
- logging.info("Bluetooth disabled on device %s %s" % (self.label, self.serial_number))
-
- # Start logcat logging
- self.logcat_output_path = os.path.join(
- self.log_path_base, '%s_%s_%s_logcat_logs.txt' % (self.type_identifier, self.label, self.serial_number))
- self.logcat_cmd = ["adb", "-s", self.serial_number, "logcat", "-T", "1", "-v", "year", "-v", "uid"]
- logging.debug("Running %s", " ".join(self.logcat_cmd))
- self.logcat_process = subprocess.Popen(self.logcat_cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- asserts.assert_true(self.logcat_process, msg="Cannot start logcat_process at " + " ".join(self.logcat_cmd))
- asserts.assert_true(is_subprocess_alive(self.logcat_process),
- msg="logcat_process stopped immediately after running " + " ".join(self.logcat_cmd))
- self.logcat_logger = AsyncSubprocessLogger(self.logcat_process, [self.logcat_output_path],
- log_to_stdout=self.verbose_mode,
- tag="%s_%s" % (self.label, self.serial_number),
- color=self.terminal_color)
-
- # Done run parent setup
- logging.info("Done preparation for %s, starting backing process" % self.serial_number)
- super().setup()
-
- def teardown(self):
- super().teardown()
- stop_signal = signal.SIGINT
- self.logcat_process.send_signal(stop_signal)
- try:
- return_code = self.logcat_process.wait(timeout=self.WAIT_FOR_DEVICE_SIGINT_TIMEOUT_SECONDS)
- except subprocess.TimeoutExpired:
- logging.error("[%s_%s] Failed to interrupt logcat process via SIGINT, sending SIGKILL" %
- (self.label, self.serial_number))
- stop_signal = signal.SIGKILL
- self.logcat_process.kill()
- try:
- return_code = self.logcat_process.wait(timeout=self.WAIT_SIGKILL_TIMEOUT_SECONDS)
- except subprocess.TimeoutExpired:
- logging.error("Failed to kill logcat_process %s %s" % (self.label, self.serial_number))
- return_code = -65536
- if return_code not in [-stop_signal, 0]:
- logging.error("logcat_process %s_%s stopped with code: %d" % (self.label, self.serial_number, return_code))
- self.logcat_logger.stop()
- self.cleanup_port_forwarding()
- self.pull_logs(self.log_path_base)
-
- def pull_logs(self, base_dir):
- try:
- self.adb.pull([
- "/data/misc/bluetooth/logs/btsnoop_hci.log",
- str(os.path.join(base_dir, "%s_btsnoop_hci.log" % self.label))
- ])
- except AdbError as error:
- # Some tests have no snoop logs, and that's OK
- if ADB_FILE_NOT_EXIST_ERROR not in str(error):
- logging.error(PULL_LOG_FILE_ERROR_MSG_PREFIX + str(error))
- try:
- self.adb.pull(
- ["/data/misc/bluedroid/bt_config.conf",
- str(os.path.join(base_dir, "%s_bt_config.conf" % self.label))])
- except AdbError as error:
- # Some tests have no config file, and that's OK
- if ADB_FILE_NOT_EXIST_ERROR not in str(error):
- logging.error(PULL_LOG_FILE_ERROR_MSG_PREFIX + str(error))
-
- def cleanup_port_forwarding(self):
- try:
- self.adb.remove_tcp_forward(self.grpc_port)
- except AdbError as error:
- msg = PORT_FORWARDING_ERROR_MSG_PREFIX + str(error)
- if "not found" in msg:
- logging.debug(msg)
- else:
- logging.error(msg)
-
- try:
- if self.grpc_root_server_port != -1:
- self.adb.remove_tcp_forward(self.grpc_root_server_port)
- except AdbError as error:
- msg = PORT_FORWARDING_ERROR_MSG_PREFIX + str(error)
- if "not found" in msg:
- logging.debug(msg)
- else:
- logging.error(msg)
-
- try:
- self.adb.reverse(["--remove", "tcp:%d" % self.signal_port])
- except AdbError as error:
- msg = PORT_FORWARDING_ERROR_MSG_PREFIX + str(error)
- if "not found" in msg:
- logging.debug(msg)
- else:
- logging.error(msg)
-
- @staticmethod
- def ensure_no_output(result):
- """
- Ensure a command has not output
- """
- asserts.assert_true(result is None or len(result) == 0,
- msg="command returned something when it shouldn't: %s" % result)
-
- def sync_device_time(self):
- self.adb.shell("settings put global auto_time 0")
- self.adb.shell("settings put global auto_time_zone 0")
- device_tz = self.adb.shell("date +%z").decode(UTF_8).rstrip()
- asserts.assert_true(device_tz, "date +%z must return device timezone, "
- "but returned {} instead".format(device_tz))
- host_tz = time.strftime("%z")
- if device_tz != host_tz:
- target_timezone = utils.get_timezone_olson_id()
- logging.debug("Device timezone %s does not match host timezone %s, "
- "syncing them by setting timezone to %s" % (device_tz, host_tz, target_timezone))
- self.adb.shell("setprop persist.sys.timezone %s" % target_timezone)
- self.reboot()
- self.adb.remount()
- device_tz = self.adb.shell("date +%z").decode(UTF_8).rstrip()
- asserts.assert_equal(
- host_tz, device_tz, "Device timezone %s still does not match host "
- "timezone %s after reset" % (device_tz, host_tz))
- self.adb.shell("date %s" % time.strftime("%m%d%H%M%Y.%S"))
- datetime_format = "%Y-%m-%dT%H:%M:%S%z"
- try:
- device_time = datetime.strptime(
- self.adb.shell("date +'%s'" % datetime_format).decode(UTF_8).rstrip(), datetime_format)
- except ValueError:
- asserts.fail("Failed to get time after sync")
- return
- # Include ADB delay that might be longer in SSH environment
- max_delta_seconds = 3
- host_time = datetime.now(tz=device_time.tzinfo)
- asserts.assert_almost_equal((device_time - host_time).total_seconds(),
- 0,
- msg="Device time %s and host time %s off by >%dms after sync" %
- (device_time.isoformat(), host_time.isoformat(), int(max_delta_seconds * 1000)),
- delta=max_delta_seconds)
-
- def push_or_die(self, src_file_path, dst_file_path, push_timeout=300, overwrite_existing=True):
- """Pushes a file to the Android device
-
- Args:
- src_file_path: The path to the file to install.
- dst_file_path: The destination of the file.
- push_timeout: How long to wait for the push to finish in seconds
- """
- if not overwrite_existing and self.adb.path_exists(dst_file_path):
- logging.debug("Skip pushing {} to {} as it already exists on device".format(src_file_path, dst_file_path))
- return
- out = self.adb.push([src_file_path, dst_file_path], timeout=push_timeout).decode(UTF_8).rstrip()
- if 'error' in out:
- asserts.fail('Unable to push file %s to %s due to %s' % (src_file_path, dst_file_path, out))
-
- def tcp_forward_or_die(self, host_port, device_port, num_retry=1):
- """
- Forward a TCP port from host to device or fail
- :param host_port: host port, int, 0 for adb to assign one
- :param device_port: device port, int
- :param num_retry: number of times to reboot and retry this before dying
- :return: host port int
- """
- error_or_port = self.adb.tcp_forward(host_port, device_port)
- if not error_or_port:
- logging.debug("host port %d was already forwarded" % host_port)
- return host_port
- if not isinstance(error_or_port, int):
- if num_retry > 0:
- # If requested, reboot an retry
- num_retry -= 1
- logging.warning("[%s] Failed to TCP forward host port %d to "
- "device port %d, num_retries left is %d" %
- (self.label, host_port, device_port, num_retry))
- self.reboot()
- self.adb.remount()
- return self.tcp_forward_or_die(host_port, device_port, num_retry=num_retry)
- asserts.fail('Unable to forward host port %d to device port %d, error %s' %
- (host_port, device_port, error_or_port))
- return error_or_port
-
- def tcp_reverse_or_die(self, device_port, host_port, num_retry=1):
- """
- Forward a TCP port from device to host or fail
- :param device_port: device port, int, 0 for adb to assign one
- :param host_port: host port, int
- :param num_retry: number of times to reboot and retry this before dying
- :return: device port int
- """
- error_or_port = self.adb.reverse(["tcp:%d" % device_port, "tcp:%d" % host_port])
- if not error_or_port:
- logging.debug("device port %d was already reversed" % device_port)
- return device_port
- try:
- error_or_port = int(error_or_port)
- except ValueError:
- if num_retry > 0:
- # If requested, reboot an retry
- num_retry -= 1
- logging.warning("[%s] Failed to TCP reverse device port %d to "
- "host port %d, num_retries left is %d" %
- (self.label, device_port, host_port, num_retry))
- self.reboot()
- self.adb.remount()
- return self.tcp_reverse_or_die(device_port, host_port, num_retry=num_retry)
- asserts.fail('Unable to reverse device port %d to host port %d, error %s' %
- (device_port, host_port, error_or_port))
- return error_or_port
-
- def ensure_verity_disabled(self):
- """Ensures that verity is enabled.
-
- If verity is not enabled, this call will reboot the phone. Note that
- this only works on debuggable builds.
- """
- logging.debug("Disabling verity and remount for %s", self.serial_number)
- # The below properties will only exist if verity has been enabled.
- system_verity = self.adb.getprop('partition.system.verified')
- vendor_verity = self.adb.getprop('partition.vendor.verified')
- if system_verity or vendor_verity:
- self.adb.disable_verity()
- self.reboot()
- self.adb.remount()
- self.adb.wait_for_device(timeout=self.WAIT_FOR_DEVICE_TIMEOUT_SECONDS)
-
- def reboot(self, timeout_minutes=15.0):
- """Reboots the device.
-
- Reboot the device, wait for device to complete booting.
- """
- logging.debug("Rebooting %s", self.serial_number)
- self.adb.reboot()
-
- timeout_start = time.time()
- timeout = timeout_minutes * 60
- # Android sometimes return early after `adb reboot` is called. This
- # means subsequent calls may make it to the device before the reboot
- # goes through, return false positives for getprops such as
- # sys.boot_completed.
- while time.time() < timeout_start + timeout:
- try:
- logging.debug("waiting for device %s to turn off", self.serial_number)
- self.adb.get_state()
- logging.debug("device %s not turned off yet", self.serial_number)
- time.sleep(.1)
- except AdbError:
- # get_state will raise an error if the device is not found. We
- # want the device to be missing to prove the device has kicked
- # off the reboot.
- logging.debug("device %s is turned off, waiting for it to boot", self.serial_number)
- break
- minutes_left = timeout_minutes - (time.time() - timeout_start) / 60.0
- self.wait_for_boot_completion(timeout_minutes=minutes_left)
- asserts.assert_true(self.adb.ensure_root(), "device %s cannot run as root after reboot" % self.serial_number)
-
- def wait_for_boot_completion(self, timeout_minutes=15.0):
- """
- Waits for Android framework to broadcast ACTION_BOOT_COMPLETED.
- :param timeout_minutes: number of minutes to wait
- """
- timeout_start = time.time()
- timeout = timeout_minutes * 60
-
- self.adb.wait_for_device(timeout=self.WAIT_FOR_DEVICE_TIMEOUT_SECONDS)
- while time.time() < timeout_start + timeout:
- try:
- completed = self.adb.getprop("sys.boot_completed")
- if completed == '1':
- return
- except AdbError:
- # adb shell calls may fail during certain period of booting
- # process, which is normal. Ignoring these errors.
- pass
- time.sleep(5)
- asserts.fail(msg='Device %s booting process timed out.' % self.serial_number)
-
- def gracefully_stop_backing_process(self):
- """
- Gracefully stops backing process
- :return: expected backing process exit code on success, 0 on error
- """
- backing_process_pid = None
- # Since we do not know which segment of self.cmd is the command running
- # on the Android device. We have to iterate with trial and error.
- cmd = self.cmd
- if len(self.cmd) >= 5:
- # skip adb -s serial shell to speed up the search
- # we don't know if any environment variables are set up before the
- # actual command and hence has to try from the 4th argument
- cmd = self.cmd[4:] + self.cmd[:4]
- for segment in cmd:
- try:
- # pgrep only takes 16 bytes including null terminator
- # -f cannot be used because that include the full command args
- current_cmd = pathlib.Path(segment).stem[:15]
- # -x matches whole command, cannot avoid as short segment may partially match
- # -n returnes the newest command matched
- backing_process_pid = int(self.adb.shell("pgrep -n -x {}".format(current_cmd)))
- logging.debug("Found backing process name on Android as {}, pid is {}".format(
- segment, backing_process_pid))
- except (AdbError, ValueError) as e:
- logging.debug("Failed to run pgrep {}".format(e))
- if backing_process_pid is not None:
- break
- if backing_process_pid is None:
- logging.warning("Failed to get pid for cmd {}".format(self.cmd))
- try:
- logging.debug(self.adb.shell("ps -A | grep bluetooth"))
- except AdbError:
- pass
- return 0
- stop_signal = signal.SIGINT
- self.adb.shell("kill -{} {}".format(stop_signal, backing_process_pid))
- logging.debug("Sent SIGINT to backing process at pid {}".format(backing_process_pid))
- stop_signal = -self.ADB_ABORT_EXIT_CODE
- return stop_signal
diff --git a/system/blueberry/tests/gd/cert/logging_client_interceptor.py b/system/blueberry/tests/gd/cert/logging_client_interceptor.py
deleted file mode 100644
index cd48395524..0000000000
--- a/system/blueberry/tests/gd/cert/logging_client_interceptor.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import grpc
-import re
-
-from blueberry.facade import common_pb2 as common
-from google.protobuf import text_format
-
-
-def custom_message_formatter(m, ident, as_one_line):
- if m.DESCRIPTOR == common.Data.DESCRIPTOR:
- return 'payload: (hex) "{}"'.format(m.payload.hex(" "))
- return None
-
-
-def pretty_print(request):
- return '{} {}'.format(
- type(request).__name__,
- text_format.MessageToString(request, as_one_line=True, message_formatter=custom_message_formatter))
-
-
-class LoggingRandezvousWrapper():
-
- def __init__(self, server_stream_call, logTag):
- if server_stream_call is None:
- raise ValueError("server_stream_call cannot be None")
- self.server_stream_call = server_stream_call
- self.logTag = logTag
-
- def cancel(self):
- self.server_stream_call.cancel()
-
- def cancelled(self):
- return self.server_stream_call.cancelled()
-
- def __iter__(self):
- return self
-
- def __next__(self):
- resp = self.server_stream_call.__next__()
- print("%s %s" % (self.logTag, pretty_print(resp)))
- return resp
-
-
-class LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor):
-
- TAG_MIN_WIDTH = 24
-
- def __init__(self, name):
- self.name = name
- self.inLogTag = "[host ▶▶▶▶▶ %s]" % self.name
- self.outLogTag = "[host ◀◀◀◀◀ %s]" % self.name
- tagLength = len(re.sub('[^\w\s]', '', self.inLogTag)) + 11
- if tagLength < self.TAG_MIN_WIDTH:
- self.inLogTag += " " * (self.TAG_MIN_WIDTH - tagLength)
- self.outLogTag += " " * (self.TAG_MIN_WIDTH - tagLength)
-
- def intercept_unary_unary(self, continuation, client_call_details, request):
- """
- This interceptor logs the requests from host
- """
- print("%s%s %s" % (self.inLogTag, client_call_details.method, pretty_print(request)))
- return continuation(client_call_details, request)
-
- def intercept_unary_stream(self, continuation, client_call_details, request):
- """
- This interceptor wraps the server response, and logs all the messages coming to host
- """
- print("%s%s %s" % (self.inLogTag, client_call_details.method, pretty_print(request)))
- server_stream_call = continuation(client_call_details, request)
- retuningMsgLogTag = self.outLogTag + client_call_details.method
- return LoggingRandezvousWrapper(server_stream_call, retuningMsgLogTag)
diff --git a/system/blueberry/tests/gd/cert/matchers.py b/system/blueberry/tests/gd/cert/matchers.py
deleted file mode 100644
index 780fe2ba08..0000000000
--- a/system/blueberry/tests/gd/cert/matchers.py
+++ /dev/null
@@ -1,295 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import logging
-import sys
-
-from blueberry.utils import bluetooth
-import hci_packets as hci
-
-
-class HciMatchers(object):
-
- @staticmethod
- def CommandComplete(opcode):
- return lambda msg: HciMatchers._is_matching_command_complete(msg.payload, opcode)
-
- @staticmethod
- def ExtractMatchingCommandComplete(packet_bytes, opcode=None):
- return HciMatchers._extract_matching_command_complete(packet_bytes, opcode)
-
- @staticmethod
- def _is_matching_command_complete(packet_bytes, opcode=None):
- return HciMatchers._extract_matching_command_complete(packet_bytes, opcode) is not None
-
- @staticmethod
- def _extract_matching_command_complete(packet_bytes, opcode=None):
- event = HciMatchers._extract_matching_event(packet_bytes, hci.EventCode.COMMAND_COMPLETE)
- if not isinstance(event, hci.CommandComplete):
- return None
- if opcode and event.command_op_code != opcode:
- return None
- return event
-
- @staticmethod
- def CommandStatus(opcode=None):
- return lambda msg: HciMatchers._is_matching_command_status(msg.payload, opcode)
-
- @staticmethod
- def ExtractMatchingCommandStatus(packet_bytes, opcode=None):
- return HciMatchers._extract_matching_command_status(packet_bytes, opcode)
-
- @staticmethod
- def _is_matching_command_status(packet_bytes, opcode=None):
- return HciMatchers._extract_matching_command_status(packet_bytes, opcode) is not None
-
- @staticmethod
- def _extract_matching_command_status(packet_bytes, opcode=None):
- event = HciMatchers._extract_matching_event(packet_bytes, hci.EventCode.COMMAND_STATUS)
- if not isinstance(event, hci.CommandStatus):
- return None
- if opcode and event.command_op_code != opcode:
- return None
- return event
-
- @staticmethod
- def EventWithCode(event_code):
- return lambda msg: HciMatchers._is_matching_event(msg.payload, event_code)
-
- @staticmethod
- def ExtractEventWithCode(packet_bytes, event_code):
- return HciMatchers._extract_matching_event(packet_bytes, event_code)
-
- @staticmethod
- def _is_matching_event(packet_bytes, event_code):
- return HciMatchers._extract_matching_event(packet_bytes, event_code) is not None
-
- @staticmethod
- def _extract_matching_event(packet_bytes, event_code):
- try:
- event = hci.Event.parse_all(packet_bytes)
- return event if event.event_code == event_code else None
- except Exception as exn:
- print(sys.stderr, f"Failed to parse incoming event: {exn}")
- print(sys.stderr, f"Event data: {' '.join([f'{b:02x}' for b in packet_bytes])}")
- return None
-
- @staticmethod
- def LeEventWithCode(subevent_code):
- return lambda msg: HciMatchers._extract_matching_le_event(msg.payload, subevent_code) is not None
-
- @staticmethod
- def ExtractLeEventWithCode(packet_bytes, subevent_code):
- return HciMatchers._extract_matching_le_event(packet_bytes, subevent_code)
-
- @staticmethod
- def _extract_matching_le_event(packet_bytes, subevent_code):
- event = HciMatchers._extract_matching_event(packet_bytes, hci.EventCode.LE_META_EVENT)
- if (not isinstance(event, hci.LeMetaEvent) or event.subevent_code != subevent_code):
- return None
-
- return event
-
- @staticmethod
- def LeAdvertisement(subevent_code=hci.SubeventCode.EXTENDED_ADVERTISING_REPORT, address=None, data=None):
- return lambda msg: HciMatchers._extract_matching_le_advertisement(msg.payload, subevent_code, address, data
- ) is not None
-
- @staticmethod
- def ExtractLeAdvertisement(packet_bytes,
- subevent_code=hci.SubeventCode.EXTENDED_ADVERTISING_REPORT,
- address=None,
- data=None):
- return HciMatchers._extract_matching_le_advertisement(packet_bytes, subevent_code, address, data)
-
- @staticmethod
- def _extract_matching_le_advertisement(packet_bytes,
- subevent_code=hci.SubeventCode.EXTENDED_ADVERTISING_REPORT,
- address=None,
- data=None):
- event = HciMatchers._extract_matching_le_event(packet_bytes, subevent_code)
- if event is None:
- return None
-
- matched = False
- for response in event.responses:
- matched |= (address == None or response.address == bluetooth.Address(address)) and (data == None or
- data in packet_bytes)
-
- return event if matched else None
-
- @staticmethod
- def LeConnectionComplete():
- return lambda msg: HciMatchers._extract_le_connection_complete(msg.payload) is not None
-
- @staticmethod
- def ExtractLeConnectionComplete(packet_bytes):
- return HciMatchers._extract_le_connection_complete(packet_bytes)
-
- @staticmethod
- def _extract_le_connection_complete(packet_bytes):
- event = HciMatchers._extract_matching_le_event(packet_bytes, hci.SubeventCode.CONNECTION_COMPLETE)
- if event is not None:
- return event
-
- return HciMatchers._extract_matching_le_event(packet_bytes, hci.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
-
- @staticmethod
- def LogEventCode():
- return lambda event: logging.info("Received event: %x" % hci.Event.parse(event.payload).event_code)
-
- @staticmethod
- def LinkKeyRequest():
- return HciMatchers.EventWithCode(hci.EventCode.LINK_KEY_REQUEST)
-
- @staticmethod
- def IoCapabilityRequest():
- return HciMatchers.EventWithCode(hci.EventCode.IO_CAPABILITY_REQUEST)
-
- @staticmethod
- def IoCapabilityResponse():
- return HciMatchers.EventWithCode(hci.EventCode.IO_CAPABILITY_RESPONSE)
-
- @staticmethod
- def UserPasskeyNotification():
- return HciMatchers.EventWithCode(hci.EventCode.USER_PASSKEY_NOTIFICATION)
-
- @staticmethod
- def UserPasskeyRequest():
- return HciMatchers.EventWithCode(hci.EventCode.USER_PASSKEY_REQUEST)
-
- @staticmethod
- def UserConfirmationRequest():
- return HciMatchers.EventWithCode(hci.EventCode.USER_CONFIRMATION_REQUEST)
-
- @staticmethod
- def LinkKeyNotification():
- return HciMatchers.EventWithCode(hci.EventCode.LINK_KEY_NOTIFICATION)
-
- @staticmethod
- def SimplePairingComplete():
- return HciMatchers.EventWithCode(hci.EventCode.SIMPLE_PAIRING_COMPLETE)
-
- @staticmethod
- def Disconnect():
- return HciMatchers.EventWithCode(hci.EventCode.DISCONNECT)
-
- @staticmethod
- def DisconnectionComplete():
- return HciMatchers.EventWithCode(hci.EventCode.DISCONNECTION_COMPLETE)
-
- @staticmethod
- def RemoteOobDataRequest():
- return HciMatchers.EventWithCode(hci.EventCode.REMOTE_OOB_DATA_REQUEST)
-
- @staticmethod
- def PinCodeRequest():
- return HciMatchers.EventWithCode(hci.EventCode.PIN_CODE_REQUEST)
-
- @staticmethod
- def LoopbackOf(packet):
- return HciMatchers.Exactly(hci.LoopbackCommand(payload=packet))
-
- @staticmethod
- def Exactly(packet):
- data = bytes(packet.serialize())
- return lambda event: data == event.payload
-
-
-class AdvertisingMatchers(object):
-
- @staticmethod
- def AdvertisingCallbackMsg(type, advertiser_id=None, status=None, data=None):
- return lambda event: True if event.message_type == type and (advertiser_id == None or advertiser_id == event.advertiser_id) \
- and (status == None or status == event.status) and (data == None or data == event.data) else False
-
- @staticmethod
- def AddressMsg(type, advertiser_id=None, address=None):
- return lambda event: True if event.message_type == type and (advertiser_id == None or advertiser_id == event.advertiser_id) \
- and (address == None or address == event.address) else False
-
-
-class ScanningMatchers(object):
-
- @staticmethod
- def ScanningCallbackMsg(type, status=None, data=None):
- return lambda event: True if event.message_type == type and (status == None or status == event.status) \
- and (data == None or data == event.data) else False
-
-
-class NeighborMatchers(object):
-
- @staticmethod
- def InquiryResult(address):
- return lambda msg: NeighborMatchers._is_matching_inquiry_result(msg.packet, address)
-
- @staticmethod
- def _is_matching_inquiry_result(packet, address):
- event = HciMatchers.ExtractEventWithCode(packet, hci.EventCode.INQUIRY_RESULT)
- if not isinstance(event, hci.InquiryResult):
- return False
- return any((bluetooth.Address(address) == response.bd_addr for response in event.responses))
-
- @staticmethod
- def InquiryResultwithRssi(address):
- return lambda msg: NeighborMatchers._is_matching_inquiry_result_with_rssi(msg.packet, address)
-
- @staticmethod
- def _is_matching_inquiry_result_with_rssi(packet, address):
- event = HciMatchers.ExtractEventWithCode(packet, hci.EventCode.INQUIRY_RESULT_WITH_RSSI)
- if not isinstance(event, hci.InquiryResultWithRssi):
- return False
- return any((bluetooth.Address(address) == response.address for response in event.responses))
-
- @staticmethod
- def ExtendedInquiryResult(address):
- return lambda msg: NeighborMatchers._is_matching_extended_inquiry_result(msg.packet, address)
-
- @staticmethod
- def _is_matching_extended_inquiry_result(packet, address):
- event = HciMatchers.ExtractEventWithCode(packet, hci.EventCode.EXTENDED_INQUIRY_RESULT)
- if not isinstance(event, (hci.ExtendedInquiryResult, hci.ExtendedInquiryResultRaw)):
- return False
- return bluetooth.Address(address) == event.address
-
-
-class SecurityMatchers(object):
-
- @staticmethod
- def UiMsg(type, address=None):
- return lambda event: True if event.message_type == type and (address == None or address == event.peer
- ) else False
-
- @staticmethod
- def BondMsg(type, address=None, reason=None):
- return lambda event: True if event.message_type == type and (address == None or address == event.peer) and (
- reason == None or reason == event.reason) else False
-
- @staticmethod
- def HelperMsg(type, address=None):
- return lambda event: True if event.message_type == type and (address == None or address == event.peer
- ) else False
-
-
-class IsoMatchers(object):
-
- @staticmethod
- def Data(payload):
- return lambda packet: packet.payload == payload
-
- @staticmethod
- def PacketPayloadWithMatchingCisHandle(cis_handle):
- return lambda packet: None if cis_handle != packet.handle else packet
diff --git a/system/blueberry/tests/gd/cert/metadata.py b/system/blueberry/tests/gd/cert/metadata.py
deleted file mode 100644
index aa1bc9a8bf..0000000000
--- a/system/blueberry/tests/gd/cert/metadata.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-import functools
-import inspect
-
-from mobly import asserts
-
-from blueberry.tests.gd.cert.test_decorators import test_info
-
-
-def _fail_decorator(msg):
-
- def fail_decorator(func):
-
- @functools.wraps(func)
- def fail(*args, **kwargs):
- asserts.fail(msg)
-
- return fail
-
- return fail_decorator
-
-
-def metadata(_do_not_use=None, pts_test_id=None, pts_test_name=None):
- """
- Record a piece of test metadata in the Extra section of the test Record in
- the test summary file. The metadata will come with a timestamp, but there
- is no guarantee on the order of when the metadata will be written
-
- Note:
- - Metadata is recorded per test case as key-value pairs.
- - Metadata is only guaranteed to be written when the test result is PASS,
- FAIL or SKIPPED. When there are test infrastructural errors, metadata
- might not be written successfully
- :param _do_not_use: a positional argument with default value. This argument
- is to ensure that @metadata(key=value) is used in a
- functional form instead of @metadata or @metadata(a)
- :param pts_test_id: A fully qualified PTS test ID such as
- L2CAP/COS/IEX/BV-01-C
- :param pts_test_name: A human readable test name such as
- "Request Connection" for the above example
- :return: decorated test case function object
- """
- if _do_not_use is not None:
-
- def fail(*args, **kwargs):
- asserts.fail("@metadata must be used in functional form such " "as @metadta(key=value)")
-
- return fail
-
- # Create a dictionary of optional parameters
- values = locals()
- args = {arg: values[arg] for arg in inspect.getfullargspec(metadata).args}
- del args["_do_not_use"]
-
- # Check if at least one optional parameter is valid
- if not any(args.values()):
- return _fail_decorator("at least one optional argument should be valid")
-
- # Validate pts_test_id and pts_test_name
- if any((pts_test_id, pts_test_name)) and \
- not all((pts_test_id, pts_test_name)):
- return _fail_decorator("pts_test_id and pts_test_name must both " "be valid if one of them is valid")
-
- return test_info(**args)
diff --git a/system/blueberry/tests/gd/cert/os_utils.py b/system/blueberry/tests/gd/cert/os_utils.py
deleted file mode 100644
index 31e4a0ebab..0000000000
--- a/system/blueberry/tests/gd/cert/os_utils.py
+++ /dev/null
@@ -1,154 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import logging
-from pathlib import Path
-import psutil
-import re
-import subprocess
-from typing import Container
-from collections import deque
-
-
-class TerminalColor:
- RED = "\033[31;1m"
- BLUE = "\033[34;1m"
- YELLOW = "\033[33;1m"
- MAGENTA = "\033[35;1m"
- END = "\033[0m"
-
-
-def is_subprocess_alive(process, timeout_seconds=1):
- """
- Check if a process is alive for at least timeout_seconds
- :param process: a Popen object that represent a subprocess
- :param timeout_seconds: process needs to be alive for at least
- timeout_seconds
- :return: True if process is alive for at least timeout_seconds
- """
- try:
- process.wait(timeout=timeout_seconds)
- return False
- except subprocess.TimeoutExpired as exp:
- return True
-
-
-def get_gd_root():
- """
- Return the root of the GD test library
-
- GD root is the parent directory of blueberry/tests/gd/cert
- :return: root directory string of gd test library
- """
- return str(Path(__file__).absolute().parents[4])
-
-
-def make_ports_available(ports: Container[int], timeout_seconds=10):
- """Make sure a list of ports are available
- kill occupying process if possible
- :param ports: list of target ports
- :param timeout_seconds: number of seconds to wait when killing processes
- :return: True on success, False on failure
- """
- if not ports:
- logging.warning("Empty ports is given to make_ports_available()")
- return True
- # Get connections whose state are in LISTEN only
- # Connections in other states won't affect binding as SO_REUSEADDR is used
- listening_conns_for_port = filter(
- lambda conn: (conn and conn.status == psutil.CONN_LISTEN and conn.laddr and conn.laddr.port in ports),
- psutil.net_connections())
- success = True
- killed_pids = set()
- for conn in listening_conns_for_port:
- logging.warning("Freeing port %d used by %s" % (conn.laddr.port, str(conn)))
- if not conn.pid:
- logging.error("Failed to kill process occupying port %d due to lack of pid" % conn.laddr.port)
- continue
- logging.warning("Killing pid %d that is using port port %d" % (conn.pid, conn.laddr.port))
- if conn.pid in killed_pids:
- logging.warning("Pid %d is already killed in previous iteration" % (conn.pid))
- continue
- try:
- process = psutil.Process(conn.pid)
- process.kill()
- process.wait(timeout=timeout_seconds)
- killed_pids.add(conn.pid)
- except psutil.NoSuchProcess:
- logging.warning("Pid %d is already dead before trying to kill it" % (conn.pid))
- killed_pids.add(conn.pid)
- continue
- except psutil.TimeoutExpired:
- logging.error("SIGKILL timeout after %d seconds for pid %d" % (timeout_seconds, conn.pid))
- success = False
- break
- return success
-
-
-# e.g. 2020-05-06 16:02:04.216 bt - packages/modules/Bluetooth/system/gd/facade/facade_main.cc:79 - crash_callback: #03 pc 0000000000013520 /lib/x86_64-linux-gnu/libpthread-2.29.so
-HOST_CRASH_LINE_REGEX = re.compile(r"^.* - crash_callback: (?P<line>.*)$")
-HOST_ABORT_HEADER = "Process crashed, signal: Aborted"
-ASAN_OUTPUT_START_REGEX = re.compile(r"^==.*AddressSanitizer.*$")
-
-
-def read_crash_snippet_and_log_tail(logpath):
- """
- Get crash snippet if regex matched or last 20 lines of log
- :return: crash_snippet, log_tail_20
- 1) crash snippet without timestamp in one string;
- 2) last 20 lines of log in one string;
- """
- gd_root_prefix = get_gd_root() + "/"
- abort_line = None
- last_20_lines = deque(maxlen=20)
- crash_log_lines = []
- asan = False
- asan_lines = []
-
- try:
- with open(logpath) as f:
- for _, line in enumerate(f):
- last_20_lines.append(line)
- asan_match = ASAN_OUTPUT_START_REGEX.match(line)
- if asan or asan_match:
- asan_lines.append(line)
- asan = True
- continue
-
- host_crash_match = HOST_CRASH_LINE_REGEX.match(line)
- if host_crash_match:
- crash_line = host_crash_match.group("line").replace(gd_root_prefix, "")
- if HOST_ABORT_HEADER in crash_line \
- and len(last_20_lines) > 1:
- abort_line = last_20_lines[-2]
- crash_log_lines.append(crash_line)
- except EnvironmentError:
- logging.error("Cannot open backing log file at {}".format(logpath))
- return None, None
-
- log_tail_20 = "".join(last_20_lines)
- crash_snippet = ""
- if abort_line is not None:
- crash_snippet += "abort log line:\n\n%s\n" % abort_line
- crash_snippet += "\n".join(crash_log_lines)
-
- if len(asan_lines) > 0:
- return "".join(asan_lines), log_tail_20
-
- if len(crash_log_lines) > 0:
- return crash_snippet, log_tail_20
-
- return None, log_tail_20
diff --git a/system/blueberry/tests/gd/cert/performance_test_logger.py b/system/blueberry/tests/gd/cert/performance_test_logger.py
deleted file mode 100644
index 006bbd6aa6..0000000000
--- a/system/blueberry/tests/gd/cert/performance_test_logger.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from datetime import datetime
-
-
-class PerformanceTestLogger(object):
- """
- A helper class to log time points and intervals
- """
-
- def __init__(self):
- self.base_timepoint = datetime.now()
- # We use a dictionary of a list of timepoints
- self.start_interval_points = {}
- self.end_interval_points = {}
- self.single_points = {}
-
- def log_single_point(self, label=""):
- if label not in self.single_points:
- self.single_points[label] = []
- self.single_points[label].append(datetime.now())
-
- def start_interval(self, label=""):
- if label not in self.start_interval_points:
- self.start_interval_points[label] = []
- self.start_interval_points[label].append(datetime.now())
-
- def end_interval(self, label=""):
- if label not in self.end_interval_points:
- self.end_interval_points[label] = []
- self.end_interval_points[label].append(datetime.now())
-
- def _check_interval_label(self, label):
- if label not in self.start_interval_points or label not in self.end_interval_points:
- raise KeyError("label %s doesn't exist" % label)
- if len(self.start_interval_points[label]) != len(self.end_interval_points[label]):
- raise KeyError("label %s doesn't have correct start and end log" % label)
-
- def get_duration_of_intervals(self, label):
- """
- Return the list of duration of the intervals with specified label.
- """
- self._check_interval_label(label)
- intervals = []
- for i in range(len(self.start_interval_points[label])):
- interval = self.end_interval_points[label][i] - self.start_interval_points[label][i]
- intervals.append(interval)
- return intervals
-
- def dump_intervals(self):
- """
- Gives an iterator of (iterator of label, start, end) over all labels
- """
- for label in self.start_interval_points:
- self._check_interval_label(label)
- yield ((label, self.start_interval_points[label][i], self.end_interval_points[label][i])
- for i in range(len(self.start_interval_points[label])))
diff --git a/system/blueberry/tests/gd/cert/pts_base_test.py b/system/blueberry/tests/gd/cert/pts_base_test.py
deleted file mode 100644
index 0e8b99a715..0000000000
--- a/system/blueberry/tests/gd/cert/pts_base_test.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-from mobly import base_test
-
-import importlib
-
-
-class PTSBaseTestClass(base_test.BaseTestClass):
-
- def __init__(self, configs):
- BaseTestClass.__init__(self, configs)
-
- gd_devices = self.controller_configs.get("GdDevice")
-
- self.register_controller(importlib.import_module('cert.gd_device'), builtin=True)
diff --git a/system/blueberry/tests/gd/cert/py_acl_manager.py b/system/blueberry/tests/gd/cert/py_acl_manager.py
deleted file mode 100644
index ddb93d2430..0000000000
--- a/system/blueberry/tests/gd/cert/py_acl_manager.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.event_stream import IEventStream
-from blueberry.tests.gd.cert.captures import HciCaptures
-from blueberry.tests.gd.cert.closable import Closable
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.facade.hci import acl_manager_facade_pb2 as acl_manager_facade
-from blueberry.utils import bluetooth
-import hci_packets as hci
-
-
-class PyAclManagerAclConnection(IEventStream, Closable):
-
- def __init__(self, acl_manager, remote_addr, handle, event_stream):
- self.acl_manager = acl_manager
- self.handle = handle
- self.remote_addr = remote_addr
- self.connection_event_stream = event_stream
- self.acl_stream = EventStream(self.acl_manager.FetchAclData(acl_manager_facade.HandleMsg(handle=self.handle)))
-
- def disconnect(self, reason):
- packet_bytes = hci.Disconnect(connection_handle=self.handle, reason=reason).serialize()
- self.acl_manager.ConnectionCommand(acl_manager_facade.ConnectionCommandMsg(packet=packet_bytes))
-
- def close(self):
- safeClose(self.connection_event_stream)
- safeClose(self.acl_stream)
-
- def wait_for_disconnection_complete(self):
- disconnection_complete = HciCaptures.DisconnectionCompleteCapture()
- assertThat(self.connection_event_stream).emits(disconnection_complete)
- self.disconnect_reason = disconnection_complete.get().reason
-
- def send(self, data):
- self.acl_manager.SendAclData(acl_manager_facade.AclData(handle=self.handle, payload=bytes(data)))
-
- def get_event_queue(self):
- return self.acl_stream.get_event_queue()
-
-
-class PyAclManager:
-
- def __init__(self, device):
- self.acl_manager = device.hci_acl_manager
- self.incoming_connection_event_stream = None
- self.outgoing_connection_event_stream = None
-
- def close(self):
- safeClose(self.incoming_connection_event_stream)
- safeClose(self.outgoing_connection_event_stream)
-
- def listen_for_an_incoming_connection(self):
- assertThat(self.incoming_connection_event_stream).isNone()
- self.incoming_connection_event_stream = EventStream(
- self.acl_manager.FetchIncomingConnection(empty_proto.Empty()))
-
- def initiate_connection(self, remote_addr):
- assertThat(self.outgoing_connection_event_stream).isNone()
- remote_addr_bytes = remote_addr if isinstance(remote_addr, bytes) else remote_addr.encode('utf-8')
- self.outgoing_connection_event_stream = EventStream(
- self.acl_manager.CreateConnection(acl_manager_facade.ConnectionMsg(address=remote_addr_bytes)))
-
- def complete_connection(self, event_stream):
- connection_complete = HciCaptures.ConnectionCompleteCapture()
- assertThat(event_stream).emits(connection_complete)
- complete = connection_complete.get()
- handle = complete.connection_handle
- address = repr(complete.bd_addr)
- return PyAclManagerAclConnection(self.acl_manager, address, handle, event_stream)
-
- def complete_incoming_connection(self):
- assertThat(self.incoming_connection_event_stream).isNotNone()
- event_stream = self.incoming_connection_event_stream
- self.incoming_connection_event_stream = None
- return self.complete_connection(event_stream)
-
- def complete_outgoing_connection(self):
- assertThat(self.outgoing_connection_event_stream).isNotNone()
- event_stream = self.outgoing_connection_event_stream
- self.outgoing_connection_event_stream = None
- return self.complete_connection(event_stream)
diff --git a/system/blueberry/tests/gd/cert/py_hal.py b/system/blueberry/tests/gd/cert/py_hal.py
deleted file mode 100644
index 074b2ddb87..0000000000
--- a/system/blueberry/tests/gd/cert/py_hal.py
+++ /dev/null
@@ -1,341 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.event_stream import FilteringEventStream
-from blueberry.tests.gd.cert.event_stream import IEventStream
-from blueberry.tests.gd.cert.closable import Closable
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.captures import HciCaptures
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert.matchers import HciMatchers
-from blueberry.facade import common_pb2 as common
-import hci_packets as hci
-from blueberry.utils import bluetooth
-
-
-class PyHalAclConnection(IEventStream):
-
- def __init__(self, handle, acl_stream, device):
- self.handle = int(handle)
- self.device = device
- self.our_acl_stream = FilteringEventStream(acl_stream, None)
-
- def send(self, pb_flag, b_flag, data: bytes):
- assert isinstance(data, bytes)
- acl = hci.Acl(handle=self.handle, packet_boundary_flag=pb_flag, broadcast_flag=b_flag, payload=data)
- self.device.hal.SendAcl(common.Data(payload=acl.serialize()))
-
- def send_first(self, data: bytes):
- assert isinstance(data, bytes)
- self.send(hci.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE, hci.BroadcastFlag.POINT_TO_POINT, data)
-
- def get_event_queue(self):
- return self.our_acl_stream.get_event_queue()
-
-
-class PyHalAdvertisement(object):
-
- def __init__(self, handle, py_hal, is_legacy):
- self.handle = handle
- self.py_hal = py_hal
- self.legacy = is_legacy
-
- def set_data(self, complete_name):
- advertising_data = [hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(complete_name))]
-
- if self.legacy:
- self.py_hal.send_hci_command(hci.LeSetAdvertisingData(advertising_data=advertising_data))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_ADVERTISING_DATA)
- else:
- self.py_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingData(advertising_handle=self.handle,
- operation=hci.Operation.COMPLETE_ADVERTISEMENT,
- fragment_preference=hci.FragmentPreference.CONTROLLER_SHOULD_NOT,
- advertising_data=advertising_data))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_ADVERTISING_DATA)
-
- def set_scan_response(self, shortened_name):
- advertising_data = [hci.GapData(data_type=hci.GapDataType.SHORTENED_LOCAL_NAME, data=list(shortened_name))]
-
- if self.legacy:
- self.py_hal.send_hci_command(hci.LeSetScanResponseData(advertising_data=advertising_data))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_SCAN_RESPONSE_DATA)
- else:
- self.py_hal.send_hci_command(
- hci.LeSetExtendedScanResponseData(advertising_handle=self.handle,
- operation=hci.Operation.COMPLETE_ADVERTISEMENT,
- fragment_preference=hci.FragmentPreference.CONTROLLER_SHOULD_NOT,
- scan_response_data=advertising_data))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_SCAN_RESPONSE_DATA)
-
- def start(self):
- if self.legacy:
- self.py_hal.send_hci_command(hci.LeSetAdvertisingEnable(advertising_enable=hci.Enable.ENABLED))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_ADVERTISING_ENABLE)
- else:
- self.py_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingEnable(enable=hci.Enable.ENABLED,
- enabled_sets=[
- hci.EnabledSet(advertising_handle=self.handle,
- duration=0,
- max_extended_advertising_events=0)
- ]))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_ADVERTISING_ENABLE)
-
- def stop(self):
- if self.legacy:
- self.py_hal.send_hci_command(hci.LeSetAdvertisingEnable(advertising_enable=hci.Enable.DISABLED))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_ADVERTISING_ENABLE)
- else:
- self.py_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingEnable(enable=hci.Enable.DISABLED,
- enabled_sets=[
- hci.EnabledSet(advertising_handle=self.handle,
- duration=0,
- max_extended_advertising_events=0)
- ]))
- self.py_hal.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_ADVERTISING_ENABLE)
-
-
-class PyHal(Closable):
-
- def __init__(self, device):
- self.device = device
-
- self.hci_event_stream = EventStream(self.device.hal.StreamEvents(empty_proto.Empty()))
- self.acl_stream = EventStream(self.device.hal.StreamAcl(empty_proto.Empty()))
-
- self.event_mask = 0x1FFF_FFFF_FFFF # Default Event Mask (Core Vol 4 [E] 7.3.1)
- self.le_event_mask = 0x0000_0000_001F # Default LE Event Mask (Core Vol 4 [E] 7.8.1)
-
- # We don't deal with SCO for now
-
- def close(self):
- safeClose(self.hci_event_stream)
- safeClose(self.acl_stream)
-
- def get_hci_event_stream(self):
- return self.hci_event_stream
-
- def wait_for_complete(self, opcode):
- assertThat(self.hci_event_stream).emits(HciMatchers.CommandComplete(opcode))
-
- def wait_for_status(self, opcode):
- assertThat(self.hci_event_stream).emits(HciMatchers.CommandStatus(opcode))
-
- def get_acl_stream(self):
- return self.acl_stream
-
- def send_hci_command(self, command: hci.Packet):
- self.device.hal.SendCommand(common.Data(payload=command.serialize()))
-
- def send_acl(self, handle, pb_flag, b_flag, data: bytes):
- acl = hci.Acl(handle=handle, packet_boundary_flag=pb_flag, broadcast_flag=b_flag, payload=data)
- self.device.hal.SendAcl(common.Data(payload=acl.serialize()))
-
- def send_acl_first(self, handle, data: bytes):
- self.send_acl(handle, hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci.BroadcastFlag.POINT_TO_POINT, data)
-
- def read_own_address(self) -> bluetooth.Address:
- self.send_hci_command(hci.ReadBdAddr())
- read_bd_addr = HciCaptures.ReadBdAddrCompleteCapture()
- assertThat(self.hci_event_stream).emits(read_bd_addr)
- return read_bd_addr.get().bd_addr
-
- def set_random_le_address(self, addr):
- self.send_hci_command(hci.LeSetRandomAddress(random_address=bluetooth.Address(addr)))
- self.wait_for_complete(hci.OpCode.LE_SET_RANDOM_ADDRESS)
-
- def set_scan_parameters(self):
- self.send_hci_command(
- hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL,
- scanning_phys=1,
- parameters=[
- hci.PhyScanParameters(le_scan_type=hci.LeScanType.ACTIVE,
- le_scan_interval=6553,
- le_scan_window=6553)
- ]))
- self.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_SCAN_PARAMETERS)
-
- def unmask_event(self, *event_codes):
- for event_code in event_codes:
- self.event_mask |= 1 << (int(event_code) - 1)
- self.send_hci_command(hci.SetEventMask(event_mask=self.event_mask))
-
- def unmask_le_event(self, *subevent_codes):
- for subevent_code in subevent_codes:
- self.le_event_mask |= 1 << (int(subevent_code) - 1)
- self.send_hci_command(hci.LeSetEventMask(le_event_mask=self.le_event_mask))
-
- def start_scanning(self):
- self.send_hci_command(
- hci.LeSetExtendedScanEnable(enable=hci.Enable.ENABLED,
- filter_duplicates=hci.FilterDuplicates.DISABLED,
- duration=0,
- period=0))
- self.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_SCAN_ENABLE)
-
- def stop_scanning(self):
- self.send_hci_command(
- hci.LeSetExtendedScanEnable(enable=hci.Enable.DISABLED,
- filter_duplicates=hci.FilterDuplicates.DISABLED,
- duration=0,
- period=0))
- self.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_SCAN_ENABLE)
-
- def reset(self):
- self.send_hci_command(hci.Reset())
- self.wait_for_complete(hci.OpCode.RESET)
-
- def enable_inquiry_and_page_scan(self):
- self.send_hci_command(hci.WriteScanEnable(scan_enable=hci.ScanEnable.INQUIRY_AND_PAGE_SCAN))
-
- def initiate_connection(self, remote_addr):
- self.send_hci_command(
- hci.CreateConnection(bd_addr=bluetooth.Address(remote_addr),
- packet_type=0xcc18,
- page_scan_repetition_mode=hci.PageScanRepetitionMode.R1,
- clock_offset=0x0,
- clock_offset_valid=hci.ClockOffsetValid.INVALID,
- allow_role_switch=hci.CreateConnectionRoleSwitch.ALLOW_ROLE_SWITCH))
-
- def accept_connection(self):
- connection_request = HciCaptures.ConnectionRequestCapture()
- assertThat(self.hci_event_stream).emits(connection_request)
-
- self.send_hci_command(
- hci.AcceptConnectionRequest(bd_addr=connection_request.get().bd_addr,
- role=hci.AcceptConnectionRequestRole.REMAIN_PERIPHERAL))
- return self.complete_connection()
-
- def complete_connection(self):
- connection_complete = HciCaptures.ConnectionCompleteCapture()
- assertThat(self.hci_event_stream).emits(connection_complete)
-
- handle = connection_complete.get().connection_handle
- return PyHalAclConnection(handle, self.acl_stream, self.device)
-
- def initiate_le_connection(self, remote_addr):
- self.send_hci_command(
- hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_PEER_ADDRESS,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
- peer_address=bluetooth.Address(remote_addr),
- initiating_phys=1,
- phy_scan_parameters=[
- hci.LeCreateConnPhyScanParameters(scan_interval=0x60,
- scan_window=0x30,
- conn_interval_min=0x18,
- conn_interval_max=0x28,
- conn_latency=0,
- supervision_timeout=0x1f4,
- min_ce_length=0,
- max_ce_length=0)
- ]))
- self.wait_for_status(hci.OpCode.LE_EXTENDED_CREATE_CONNECTION)
-
- def add_to_filter_accept_list(self, remote_addr):
- self.send_hci_command(
- hci.LeAddDeviceToFilterAcceptList(address_type=hci.FilterAcceptListAddressType.RANDOM,
- address=bluetooth.Address(remote_addr)))
-
- def initiate_le_connection_by_filter_accept_list(self, remote_addr):
- self.send_hci_command(
- hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_FILTER_ACCEPT_LIST,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
- peer_address=bluetooth.Address('00:00:00:00:00:00'),
- initiating_phys=1,
- phy_scan_parameters=[
- hci.LeCreateConnPhyScanParameters(scan_interval=0x60,
- scan_window=0x30,
- conn_interval_min=0x18,
- conn_interval_max=0x28,
- conn_latency=0,
- supervision_timeout=0x1f4,
- min_ce_length=0,
- max_ce_length=0)
- ]))
-
- def complete_le_connection(self):
- connection_complete = HciCaptures.LeConnectionCompleteCapture()
- assertThat(self.hci_event_stream).emits(connection_complete)
-
- handle = connection_complete.get().connection_handle
- return PyHalAclConnection(handle, self.acl_stream, self.device)
-
- def create_advertisement(self,
- handle,
- own_address: str,
- properties=hci.LegacyAdvertisingEventProperties.ADV_IND,
- min_interval=400,
- max_interval=450,
- channel_map=7,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- peer_address='00:00:00:00:00:00',
- filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES,
- tx_power=0xF8,
- sid=1,
- scan_request_notification=hci.Enable.DISABLED):
-
- self.send_hci_command(
- hci.LeSetExtendedAdvertisingParametersLegacy(advertising_handle=handle,
- legacy_advertising_event_properties=properties,
- primary_advertising_interval_min=min_interval,
- primary_advertising_interval_max=max_interval,
- primary_advertising_channel_map=channel_map,
- own_address_type=own_address_type,
- peer_address_type=peer_address_type,
- peer_address=bluetooth.Address(peer_address),
- advertising_filter_policy=filter_policy,
- advertising_tx_power=tx_power,
- advertising_sid=sid,
- scan_request_notification_enable=scan_request_notification))
- self.wait_for_complete(hci.OpCode.LE_SET_EXTENDED_ADVERTISING_PARAMETERS)
- self.send_hci_command(
- hci.LeSetAdvertisingSetRandomAddress(advertising_handle=handle,
- random_address=bluetooth.Address(own_address)))
- self.wait_for_complete(hci.OpCode.LE_SET_ADVERTISING_SET_RANDOM_ADDRESS)
-
- return PyHalAdvertisement(handle, self, False)
-
- def create_legacy_advertisement(self,
- advertising_type=hci.AdvertisingType.ADV_IND,
- min_interval=400,
- max_interval=450,
- channel_map=7,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- peer_address='00:00:00:00:00:00',
- filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES):
-
- self.send_hci_command(
- hci.LeSetAdvertisingParameters(advertising_interval_min=min_interval,
- advertising_interval_max=max_interval,
- advertising_type=advertising_type,
- own_address_type=own_address_type,
- peer_address_type=peer_address_type,
- peer_address=bluetooth.Address(peer_address),
- advertising_channel_map=channel_map,
- advertising_filter_policy=filter_policy))
- self.wait_for_complete(hci.OpCode.LE_SET_ADVERTISING_PARAMETERS)
-
- return PyHalAdvertisement(None, self, True)
diff --git a/system/blueberry/tests/gd/cert/py_hci.py b/system/blueberry/tests/gd/cert/py_hci.py
deleted file mode 100644
index 67460657c9..0000000000
--- a/system/blueberry/tests/gd/cert/py_hci.py
+++ /dev/null
@@ -1,294 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-from datetime import timedelta
-
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.event_stream import FilteringEventStream
-from blueberry.tests.gd.cert.event_stream import IEventStream
-from blueberry.tests.gd.cert.closable import Closable
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.captures import HciCaptures
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.facade.hci import hci_facade_pb2 as hci_facade
-from blueberry.facade import common_pb2 as common
-from blueberry.tests.gd.cert.matchers import HciMatchers
-import hci_packets as hci
-import blueberry.utils.bluetooth as bluetooth
-
-
-class PyHciAclConnection(IEventStream):
-
- def __init__(self, handle, acl_stream, device):
- self.handle = int(handle)
- self.device = device
- # todo, handle we got is 0, so doesn't match - fix before enabling filtering
- self.our_acl_stream = FilteringEventStream(acl_stream, None)
-
- def send(self, pb_flag, b_flag, data: bytes):
- assert isinstance(data, bytes)
- acl = hci.Acl(handle=self.handle, packet_boundary_flag=pb_flag, broadcast_flag=b_flag, payload=data)
- self.device.hci.SendAcl(common.Data(payload=acl.serialize()))
-
- def send_first(self, data: bytes):
- self.send(hci.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE, hci.BroadcastFlag.POINT_TO_POINT, data)
-
- def send_continuing(self, data):
- self.send(hci.PacketBoundaryFlag.CONTINUING_FRAGMENT, hci.BroadcastFlag.POINT_TO_POINT, data)
-
- def get_event_queue(self):
- return self.our_acl_stream.get_event_queue()
-
-
-class PyHciLeAclConnection(IEventStream):
-
- def __init__(self, handle, acl_stream, device, peer, peer_type, peer_resolvable, local_resolvable):
- self.handle = int(handle)
- self.device = device
- self.peer = peer
- self.peer_type = peer_type
- self.peer_resolvable = peer_resolvable
- self.local_resolvable = local_resolvable
- # todo, handle we got is 0, so doesn't match - fix before enabling filtering
- self.our_acl_stream = FilteringEventStream(acl_stream, None)
-
- def send(self, pb_flag, b_flag, data: bytes):
- assert isinstance(data, bytes)
- acl = hci.Acl(handle=self.handle, packet_boundary_flag=pb_flag, broadcast_flag=b_flag, payload=data)
- self.device.hci.SendAcl(common.Data(payload=acl.serialize()))
-
- def send_first(self, data: bytes):
- self.send(hci.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE, hci.BroadcastFlag.POINT_TO_POINT, data)
-
- def send_continuing(self, data: bytes):
- self.send(hci.PacketBoundaryFlag.CONTINUING_FRAGMENT, hci.BroadcastFlag.POINT_TO_POINT, data)
-
- def get_event_queue(self):
- return self.our_acl_stream.get_event_queue()
-
- def local_resolvable_address(self):
- return self.local_resolvable
-
- def peer_resolvable_address(self):
- return self.peer_resolvable
-
- def peer_address(self):
- return self.peer
-
-
-class PyHciAdvertisement(object):
-
- def __init__(self, handle, py_hci):
- self.handle = handle
- self.py_hci = py_hci
-
- def set_data(self, complete_name):
- self.py_hci.send_command(
- hci.LeSetExtendedAdvertisingData(
- advertising_handle=self.handle,
- operation=hci.Operation.COMPLETE_ADVERTISEMENT,
- fragment_preference=hci.FragmentPreference.CONTROLLER_SHOULD_NOT,
- advertising_data=[hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME,
- data=list(complete_name))]))
-
- def set_scan_response(self, shortened_name):
- self.py_hci.send_command(
- hci.LeSetExtendedScanResponseData(advertising_handle=self.handle,
- operation=hci.Operation.COMPLETE_ADVERTISEMENT,
- fragment_preference=hci.FragmentPreference.CONTROLLER_SHOULD_NOT,
- scan_response_data=[
- hci.GapData(data_type=hci.GapDataType.SHORTENED_LOCAL_NAME,
- data=list(shortened_name))
- ]))
-
- def start(self):
- self.py_hci.send_command(
- hci.LeSetExtendedAdvertisingEnable(enable=hci.Enable.ENABLED,
- enabled_sets=[
- hci.EnabledSet(advertising_handle=self.handle,
- duration=0,
- max_extended_advertising_events=0)
- ]))
- assertThat(self.py_hci.get_event_stream()).emits(
- HciMatchers.CommandComplete(hci.OpCode.LE_SET_EXTENDED_ADVERTISING_ENABLE))
-
-
-class PyHci(Closable):
-
- event_stream = None
- le_event_stream = None
- acl_stream = None
-
- def __init__(self, device, acl_streaming=False):
- """
- If you are planning on personally using the ACL data stream
- coming from HCI, specify acl_streaming=True. You probably only
- want this if you are testing HCI itself.
- """
- self.device = device
- self.event_stream = EventStream(self.device.hci.StreamEvents(empty_proto.Empty()))
- self.le_event_stream = EventStream(self.device.hci.StreamLeSubevents(empty_proto.Empty()))
- if acl_streaming:
- self.register_for_events(hci.EventCode.ROLE_CHANGE, hci.EventCode.CONNECTION_REQUEST,
- hci.EventCode.CONNECTION_COMPLETE, hci.EventCode.CONNECTION_PACKET_TYPE_CHANGED)
- self.register_for_le_events(hci.SubeventCode.ENHANCED_CONNECTION_COMPLETE)
- self.acl_stream = EventStream(self.device.hci.StreamAcl(empty_proto.Empty()))
-
- def close(self):
- safeClose(self.event_stream)
- safeClose(self.le_event_stream)
- safeClose(self.acl_stream)
-
- def get_event_stream(self):
- return self.event_stream
-
- def get_le_event_stream(self):
- return self.le_event_stream
-
- def get_raw_acl_stream(self):
- if self.acl_stream is None:
- raise Exception("Please construct '%s' with acl_streaming=True!" % self.__class__.__name__)
- return self.acl_stream
-
- def register_for_events(self, *event_codes):
- for event_code in event_codes:
- self.device.hci.RequestEvent(hci_facade.EventRequest(code=int(event_code)))
-
- def register_for_le_events(self, *event_codes):
- for event_code in event_codes:
- self.device.hci.RequestLeSubevent(hci_facade.EventRequest(code=int(event_code)))
-
- def send_command(self, command: hci.Packet):
- self.device.hci.SendCommand(common.Data(payload=command.serialize()))
-
- def enable_inquiry_and_page_scan(self):
- self.send_command(hci.WriteScanEnable(scan_enable=hci.ScanEnable.INQUIRY_AND_PAGE_SCAN))
-
- def read_own_address(self) -> bluetooth.Address:
- self.send_command(hci.ReadBdAddr())
- read_bd_addr = HciCaptures.ReadBdAddrCompleteCapture()
- assertThat(self.event_stream).emits(read_bd_addr)
- return read_bd_addr.get().bd_addr
-
- def initiate_connection(self, remote_addr):
- self.send_command(
- hci.CreateConnection(bd_addr=bluetooth.Address(remote_addr),
- packet_type=0xcc18,
- page_scan_repetition_mode=hci.PageScanRepetitionMode.R1,
- clock_offset=0x0,
- clock_offset_valid=hci.ClockOffsetValid.INVALID,
- allow_role_switch=hci.CreateConnectionRoleSwitch.ALLOW_ROLE_SWITCH))
-
- def accept_connection(self):
- connection_request = HciCaptures.ConnectionRequestCapture()
- assertThat(self.event_stream).emits(connection_request)
-
- self.send_command(
- hci.AcceptConnectionRequest(bd_addr=bluetooth.Address(connection_request.get().bd_addr),
- role=hci.AcceptConnectionRequestRole.REMAIN_PERIPHERAL))
- return self.complete_connection()
-
- def complete_connection(self):
- connection_complete = HciCaptures.ConnectionCompleteCapture()
- assertThat(self.event_stream).emits(connection_complete)
-
- handle = connection_complete.get().connection_handle
- if self.acl_stream is None:
- raise Exception("Please construct '%s' with acl_streaming=True!" % self.__class__.__name__)
- return PyHciAclConnection(handle, self.acl_stream, self.device)
-
- def set_random_le_address(self, addr):
- self.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address(addr)))
- assertThat(self.event_stream).emits(HciMatchers.CommandComplete(hci.OpCode.LE_SET_RANDOM_ADDRESS))
-
- def initiate_le_connection(self, remote_addr):
- self.send_command(
- hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_PEER_ADDRESS,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
- peer_address=bluetooth.Address(remote_addr),
- initiating_phys=1,
- phy_scan_parameters=[
- hci.LeCreateConnPhyScanParameters(scan_interval=0x60,
- scan_window=0x30,
- conn_interval_min=0x18,
- conn_interval_max=0x28,
- conn_latency=0,
- supervision_timeout=0x1f4,
- min_ce_length=0,
- max_ce_length=0)
- ]))
- assertThat(self.event_stream).emits(HciMatchers.CommandStatus(hci.OpCode.LE_EXTENDED_CREATE_CONNECTION))
-
- def incoming_le_connection(self):
- connection_complete = HciCaptures.LeConnectionCompleteCapture()
- assertThat(self.le_event_stream).emits(connection_complete)
-
- handle = connection_complete.get().connection_handle
- peer = connection_complete.get().peer_address
- peer_type = connection_complete.get().peer_address_type
- local_resolvable = connection_complete.get().local_resolvable_private_address
- peer_resolvable = connection_complete.get().peer_resolvable_private_address
- if self.acl_stream is None:
- raise Exception("Please construct '%s' with acl_streaming=True!" % self.__class__.__name__)
- return PyHciLeAclConnection(handle, self.acl_stream, self.device, repr(peer), peer_type, repr(peer_resolvable),
- repr(local_resolvable))
-
- def incoming_le_connection_fails(self):
- connection_complete = HciCaptures.LeConnectionCompleteCapture()
- assertThat(self.le_event_stream).emitsNone(connection_complete, timeout=timedelta(seconds=5))
-
- def add_device_to_resolving_list(self, peer_address_type, peer_address, peer_irk, local_irk):
- self.send_command(
- hci.LeAddDeviceToResolvingList(peer_identity_address_type=peer_address_type,
- peer_identity_address=bluetooth.Address(peer_address),
- peer_irk=peer_irk,
- local_irk=local_irk))
-
- def create_advertisement(self,
- handle,
- own_address: str,
- properties=hci.LegacyAdvertisingEventProperties.ADV_IND,
- min_interval=400,
- max_interval=450,
- channel_map=7,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- peer_address='00:00:00:00:00:00',
- filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES,
- tx_power=0xF8,
- sid=1,
- scan_request_notification=hci.Enable.DISABLED):
-
- self.send_command(
- hci.LeSetExtendedAdvertisingParametersLegacy(advertising_handle=handle,
- legacy_advertising_event_properties=properties,
- primary_advertising_interval_min=min_interval,
- primary_advertising_interval_max=max_interval,
- primary_advertising_channel_map=channel_map,
- own_address_type=own_address_type,
- peer_address_type=peer_address_type,
- peer_address=bluetooth.Address(peer_address),
- advertising_filter_policy=filter_policy,
- advertising_tx_power=tx_power,
- advertising_sid=sid,
- scan_request_notification_enable=scan_request_notification))
-
- self.send_command(
- hci.LeSetAdvertisingSetRandomAddress(advertising_handle=handle,
- random_address=bluetooth.Address(own_address)))
-
- return PyHciAdvertisement(handle, self)
diff --git a/system/blueberry/tests/gd/cert/py_le_acl_manager.py b/system/blueberry/tests/gd/cert/py_le_acl_manager.py
deleted file mode 100644
index 94540a6b23..0000000000
--- a/system/blueberry/tests/gd/cert/py_le_acl_manager.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from google.protobuf import empty_pb2 as empty_proto
-
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.event_stream import IEventStream
-from blueberry.tests.gd.cert.captures import HciCaptures
-from blueberry.tests.gd.cert.closable import Closable
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.truth import assertThat
-from datetime import timedelta
-from blueberry.facade.hci import le_acl_manager_facade_pb2 as le_acl_manager_facade
-import hci_packets as hci
-
-
-class PyLeAclManagerAclConnection(IEventStream, Closable):
-
- def __init__(self, le_acl_manager, address, remote_addr, remote_addr_type, handle, event_stream):
- """
- An abstract representation for an LE ACL connection in GD certification test
- :param le_acl_manager: The LeAclManager from this GD device
- :param address: The local device address
- :param remote_addr: Remote device address
- :param remote_addr_type: Remote device address type
- :param handle: Connection handle
- :param event_stream: The connection event stream for this connection
- """
- self.le_acl_manager = le_acl_manager
- # todo enable filtering after sorting out handles
- # self.our_acl_stream = FilteringEventStream(acl_stream, None)
- self.handle = handle
- self.connection_event_stream = event_stream
- self.acl_stream = EventStream(
- self.le_acl_manager.FetchAclData(le_acl_manager_facade.LeHandleMsg(handle=self.handle)))
- self.remote_address = remote_addr
- self.remote_address_type = remote_addr_type
- self.own_address = address
- self.disconnect_reason = None
-
- def close(self):
- safeClose(self.connection_event_stream)
- safeClose(self.acl_stream)
-
- def disconnect(self):
- self.le_acl_manager.Disconnect(le_acl_manager_facade.LeHandleMsg(handle=self.handle))
-
- def wait_for_disconnection_complete(self, timeout=timedelta(seconds=30)):
- disconnection_complete = HciCaptures.DisconnectionCompleteCapture()
- assertThat(self.connection_event_stream).emits(disconnection_complete, timeout=timeout)
- self.disconnect_reason = disconnection_complete.get().reason
-
- def send(self, data):
- self.le_acl_manager.SendAclData(le_acl_manager_facade.LeAclData(handle=self.handle, payload=bytes(data)))
-
- def get_event_queue(self):
- return self.acl_stream.get_event_queue()
-
-
-class PyLeAclManager(Closable):
-
- def __init__(self, device):
- """
- LE ACL Manager for GD Certification test
- :param device: The GD device
- """
- self.le_acl_manager = device.hci_le_acl_manager
-
- self.incoming_connection_event_stream = None
- self.outgoing_connection_event_streams = {}
- self.active_connections = []
- self.next_token = 1
-
- def close(self):
- safeClose(self.incoming_connection_event_stream)
- for v in self.outgoing_connection_event_streams.values():
- safeClose(v[0])
- for connection in self.active_connections:
- safeClose(connection)
-
- def listen_for_incoming_connections(self):
- assertThat(self.incoming_connection_event_stream).isNone()
- self.incoming_connection_event_stream = EventStream(
- self.le_acl_manager.FetchIncomingConnection(empty_proto.Empty()))
-
- def connect_to_remote(self, remote_addr):
- token = self.initiate_connection(remote_addr)
- return self.complete_outgoing_connection(token)
-
- def wait_for_connection(self):
- self.listen_for_incoming_connections()
- return self.complete_incoming_connection()
-
- def wait_for_connection_fail(self, token):
- assertThat(self.outgoing_connection_event_streams[token]).isNotNone()
- event_stream = self.outgoing_connection_event_streams[token][0]
- connection_fail = HciCaptures.LeConnectionCompleteCapture()
- assertThat(event_stream).emits(connection_fail, timeout=timedelta(seconds=35))
- complete = connection_fail.get()
- assertThat(complete.status == hci.ErrorCode.CONNECTION_ACCEPT_TIMEOUT).isTrue()
-
- def cancel_connection(self, token):
- assertThat(token in self.outgoing_connection_event_streams).isTrue()
- pair = self.outgoing_connection_event_streams.pop(token)
- safeClose(pair[0])
- self.le_acl_manager.CancelConnection(pair[1])
-
- def initiate_connection(self, remote_addr, is_direct=True):
- assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse()
- create_connection_msg = le_acl_manager_facade.CreateConnectionMsg(peer_address=remote_addr, is_direct=is_direct)
- self.outgoing_connection_event_streams[self.next_token] = EventStream(
- self.le_acl_manager.CreateConnection(create_connection_msg)), remote_addr
- token = self.next_token
- self.next_token += 1
- return token
-
- def is_on_background_list(self, remote_addr):
- return self.le_acl_manager.IsOnBackgroundList(
- le_acl_manager_facade.BackgroundRequestMsg(peer_address=remote_addr))
-
- def remove_from_background_list(self, remote_addr):
- self.le_acl_manager.RemoveFromBackgroundList(
- le_acl_manager_facade.BackgroundRequestMsg(peer_address=remote_addr))
-
- def complete_connection(self, event_stream):
- connection_complete = HciCaptures.LeConnectionCompleteCapture()
- assertThat(event_stream).emits(connection_complete)
- complete = connection_complete.get()
- handle = complete.connection_handle
- remote = repr(complete.peer_address)
- remote_address_type = complete.peer_address_type
- if complete.subevent_code == hci.SubeventCode.ENHANCED_CONNECTION_COMPLETE:
- address = complete.local_resolvable_private_address
- else:
- address = None
- connection = PyLeAclManagerAclConnection(self.le_acl_manager, address, remote, remote_address_type, handle,
- event_stream)
- self.active_connections.append(connection)
- return connection
-
- def complete_incoming_connection(self):
- assertThat(self.incoming_connection_event_stream).isNotNone()
- event_stream = self.incoming_connection_event_stream
- self.incoming_connection_event_stream = None
- return self.complete_connection(event_stream)
-
- def complete_outgoing_connection(self, token):
- assertThat(self.outgoing_connection_event_streams[token]).isNotNone()
- event_stream = self.outgoing_connection_event_streams.pop(token)[0]
- return self.complete_connection(event_stream)
diff --git a/system/blueberry/tests/gd/cert/test_decorators.py b/system/blueberry/tests/gd/cert/test_decorators.py
deleted file mode 100644
index 453062e269..0000000000
--- a/system/blueberry/tests/gd/cert/test_decorators.py
+++ /dev/null
@@ -1,267 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2017 - 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.
-
-from mobly import signals
-
-
-def test_info(predicate=None, **keyed_info):
- """Adds info about test.
-
- Extra info to include about the test. This info will be available in the
- test output. Note that if a key is given multiple times it will be added
- as a list of all values. If multiples of these are stacked their results
- will be merged.
-
- Example:
- # This test will have a variable my_var
- @test_info(my_var='THIS IS MY TEST')
- def my_test(self):
- return False
-
- Args:
- predicate: A func to call that if false will skip adding this test
- info. Function signature is bool(test_obj, args, kwargs)
- **keyed_info: The key, value info to include in the extras for this
- test.
- """
-
- def test_info_decorator(func):
- return _TestInfoDecoratorFunc(func, predicate, keyed_info)
-
- return test_info_decorator
-
-
-def __select_last(test_signals, _):
- return test_signals[-1]
-
-
-def repeated_test(num_passes, acceptable_failures=0, result_selector=__select_last):
- """A decorator that runs a test case multiple times.
-
- This decorator can be used to run a test multiple times and aggregate the
- data into a single test result. By setting `result_selector`, the user can
- access the returned result of each run, allowing them to average results,
- return the median, or gather and return standard deviation values.
-
- This decorator should be used on test cases, and should not be used on
- static or class methods. The test case must take in an additional argument,
- `attempt_number`, which returns the current attempt number, starting from
- 1.
-
- Note that any TestSignal intended to abort or skip the test will take
- abort or skip immediately.
-
- Args:
- num_passes: The number of times the test needs to pass to report the
- test case as passing.
- acceptable_failures: The number of failures accepted. If the failures
- exceeds this number, the test will stop repeating. The maximum
- number of runs is `num_passes + acceptable_failures`. If the test
- does fail, result_selector will still be called.
- result_selector: A lambda that takes in the list of TestSignals and
- returns the test signal to report the test case as. Note that the
- list also contains any uncaught exceptions from the test execution.
- """
-
- def decorator(func):
- if not func.__name__.startswith('test_'):
- raise ValueError('Tests must start with "test_".')
-
- def test_wrapper(self):
- num_failures = 0
- num_seen_passes = 0
- test_signals_received = []
- for i in range(num_passes + acceptable_failures):
- try:
- func(self, i + 1)
- except (signals.TestFailure, signals.TestError, AssertionError) as signal:
- test_signals_received.append(signal)
- num_failures += 1
- except signals.TestPass as signal:
- test_signals_received.append(signal)
- num_seen_passes += 1
- except (signals.TestSignal, KeyboardInterrupt):
- raise
- except Exception as signal:
- test_signals_received.append(signal)
- num_failures += 1
- else:
- num_seen_passes += 1
- test_signals_received.append(
- signals.TestPass('Test iteration %s of %s passed without details.' % (i, func.__name__)))
-
- if num_failures > acceptable_failures:
- break
- elif num_seen_passes == num_passes:
- break
- else:
- self.teardown_test()
- self.setup_test()
-
- raise result_selector(test_signals_received, self)
-
- return test_wrapper
-
- return decorator
-
-
-def test_tracker_info(uuid, extra_environment_info=None, predicate=None):
- """Decorator for adding test tracker info to tests results.
-
- Will add test tracker info inside of Extras/test_tracker_info.
-
- Example:
- # This test will be linked to test tracker uuid abcd
- @test_tracker_info(uuid='abcd')
- def my_test(self):
- return False
-
- Args:
- uuid: The uuid of the test case in test tracker.
- extra_environment_info: Extra info about the test tracker environment.
- predicate: A func that if false when called will ignore this info.
- """
- return test_info(test_tracker_uuid=uuid, test_tracker_environment_info=extra_environment_info, predicate=predicate)
-
-
-class _TestInfoDecoratorFunc(object):
- """Object that acts as a function decorator test info."""
-
- def __init__(self, func, predicate, keyed_info):
- self.func = func
- self.predicate = predicate
- self.keyed_info = keyed_info
- self.__name__ = func.__name__
- self.__doc__ = func.__doc__
- self.__module__ = func.__module__
-
- def __get__(self, instance, owner):
- """Called by Python to create a binding for an instance closure.
-
- When called by Python this object will create a special binding for
- that instance. That binding will know how to interact with this
- specific decorator.
- """
- return _TestInfoBinding(self, instance)
-
- def __call__(self, *args, **kwargs):
- """
- When called runs the underlying func and then attaches test info
- to a signal.
- """
- cause = None
- try:
- result = self.func(*args, **kwargs)
-
- if result or result is None:
- new_signal = signals.TestPass('')
- else:
- new_signal = signals.TestFailure('')
- except signals.TestSignal as signal:
- new_signal = signal
- except Exception as ex:
- cause = ex
- new_signal = signals.TestError(cause)
-
- if new_signal.extras is None:
- new_signal.extras = {}
- if not isinstance(new_signal.extras, dict):
- raise ValueError('test_info can only append to signal data that has a dict as the extra value.')
-
- gathered_extras = self._gather_local_info(None, *args, **kwargs)
- for k, v in gathered_extras.items():
- if k not in new_signal.extras:
- new_signal.extras[k] = v
- else:
- if not isinstance(new_signal.extras[k], list):
- new_signal.extras[k] = [new_signal.extras[k]]
-
- new_signal.extras[k].insert(0, v)
-
- raise new_signal from cause
-
- def gather(self, *args, **kwargs):
- """
- Gathers the info from this decorator without invoking the underlying
- function. This will also gather all child info if the underlying func
- has that ability.
-
- Returns: A dictionary of info.
- """
- if hasattr(self.func, 'gather'):
- extras = self.func.gather(*args, **kwargs)
- else:
- extras = {}
-
- self._gather_local_info(extras, *args, **kwargs)
-
- return extras
-
- def _gather_local_info(self, gather_into, *args, **kwargs):
- """Gathers info from this decorator and ignores children.
-
- Args:
- gather_into: Gathers into a dictionary that already exists.
-
- Returns: The dictionary with gathered info in it.
- """
- if gather_into is None:
- extras = {}
- else:
- extras = gather_into
- if not self.predicate or self.predicate(args, kwargs):
- for k, v in self.keyed_info.items():
- if v and k not in extras:
- extras[k] = v
- elif v and k in extras:
- if not isinstance(extras[k], list):
- extras[k] = [extras[k]]
- extras[k].insert(0, v)
-
- return extras
-
-
-class _TestInfoBinding(object):
- """
- When Python creates an instance of an object it creates a binding object
- for each closure that contains what the instance variable should be when
- called. This object is a similar binding for _TestInfoDecoratorFunc.
- When Python tries to create a binding of a _TestInfoDecoratorFunc it
- will return one of these objects to hold the instance for that closure.
- """
-
- def __init__(self, target, instance):
- """
- Args:
- target: The target for creating a binding to.
- instance: The instance to bind the target with.
- """
- self.target = target
- self.instance = instance
- self.__name__ = target.__name__
-
- def __call__(self, *args, **kwargs):
- """
- When this object is called it will call the target with the bound
- instance.
- """
- return self.target(self.instance, *args, **kwargs)
-
- def gather(self, *args, **kwargs):
- """
- Will gather the target with the bound instance.
- """
- return self.target.gather(self.instance, *args, **kwargs)
diff --git a/system/blueberry/tests/gd/cert/tracelogger.py b/system/blueberry/tests/gd/cert/tracelogger.py
deleted file mode 100644
index a4e5a2203c..0000000000
--- a/system/blueberry/tests/gd/cert/tracelogger.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import inspect
-import os
-
-
-class TraceLogger(object):
-
- def __init__(self, logger):
- self._logger = logger
-
- @staticmethod
- def _get_trace_info(level=1, offset=2):
- # We want the stack frame above this and above the error/warning/info
- inspect_stack = inspect.stack()
- trace_info = ''
- for i in range(level):
- try:
- stack_frames = inspect_stack[offset + i]
- info = inspect.getframeinfo(stack_frames[0])
- trace_info = '%s[%s:%s:%s]' % (trace_info, os.path.basename(info.filename), info.function, info.lineno)
- except IndexError:
- break
- return trace_info
-
- def _log_with(self, logging_lambda, trace_level, msg, *args, **kwargs):
- trace_info = TraceLogger._get_trace_info(level=trace_level, offset=3)
- logging_lambda('%s %s' % (msg, trace_info), *args, **kwargs)
-
- def exception(self, msg, *args, **kwargs):
- self._log_with(self._logger.exception, 5, msg, *args, **kwargs)
-
- def debug(self, msg, *args, **kwargs):
- self._log_with(self._logger.debug, 3, msg, *args, **kwargs)
-
- def error(self, msg, *args, **kwargs):
- self._log_with(self._logger.error, 3, msg, *args, **kwargs)
-
- def warn(self, msg, *args, **kwargs):
- self._log_with(self._logger.warn, 3, msg, *args, **kwargs)
-
- def warning(self, msg, *args, **kwargs):
- self._log_with(self._logger.warning, 3, msg, *args, **kwargs)
-
- def info(self, msg, *args, **kwargs):
- self._log_with(self._logger.info, 1, msg, *args, **kwargs)
-
- def __getattr__(self, name):
- return getattr(self._logger, name)
diff --git a/system/blueberry/tests/gd/cert/truth.py b/system/blueberry/tests/gd/cert/truth.py
deleted file mode 100644
index e3133eb435..0000000000
--- a/system/blueberry/tests/gd/cert/truth.py
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from datetime import timedelta
-
-from mobly.asserts import assert_true
-from mobly.asserts import assert_false
-from mobly import signals
-
-from blueberry.tests.gd.cert.event_stream import IEventStream
-from blueberry.tests.gd.cert.event_stream import NOT_FOR_YOU_assert_event_occurs
-from blueberry.tests.gd.cert.event_stream import NOT_FOR_YOU_assert_all_events_occur
-from blueberry.tests.gd.cert.event_stream import NOT_FOR_YOU_assert_none_matching
-from blueberry.tests.gd.cert.event_stream import NOT_FOR_YOU_assert_none
-
-
-class ObjectSubject(object):
-
- def __init__(self, value):
- self._value = value
-
- def isEqualTo(self, other):
- if self._value != other:
- raise signals.TestFailure("Expected \"%s\" to be equal to \"%s\"" % (self._value, other), extras=None)
-
- def isNotEqualTo(self, other):
- if self._value == other:
- raise signals.TestFailure("Expected \"%s\" not to be equal to \"%s\"" % (self._value, other), extras=None)
-
- def isGreaterThan(self, other):
- if self._value <= other:
- raise signals.TestFailure("Expected \"%s\" to be greater than \"%s\"" % (self._value, other), extras=None)
-
- def isLessThan(self, other):
- if self._value >= other:
- raise signals.TestFailure("Expected \"%s\" to be less than \"%s\"" % (self._value, other), extras=None)
-
- def isNone(self):
- if self._value is not None:
- raise signals.TestFailure("Expected \"%s\" to be None" % self._value, extras=None)
-
- def isNotNone(self):
- if self._value is None:
- raise signals.TestFailure("Expected \"%s\" to not be None" % self._value, extras=None)
-
-
-DEFAULT_TIMEOUT = timedelta(seconds=30)
-
-
-class EventStreamSubject(ObjectSubject):
-
- def __init__(self, value):
- super().__init__(value)
-
- def emits(self, *match_fns, at_least_times=1, timeout=DEFAULT_TIMEOUT):
- if len(match_fns) == 0:
- raise signals.TestFailure("Must specify a match function")
- elif len(match_fns) == 1:
- NOT_FOR_YOU_assert_event_occurs(self._value, match_fns[0], at_least_times=at_least_times, timeout=timeout)
- return EventStreamContinuationSubject(self._value)
- else:
- return MultiMatchStreamSubject(self._value, match_fns, timeout)
-
- def emitsNone(self, *match_fns, timeout):
- if len(match_fns) == 0:
- NOT_FOR_YOU_assert_none(self._value, timeout=timeout)
- return EventStreamContinuationSubject(self._value)
- elif len(match_fns) == 1:
- NOT_FOR_YOU_assert_none_matching(self._value, match_fns[0], timeout=timeout)
- return EventStreamContinuationSubject(self._value)
- else:
- raise signals.TestFailure("Cannot specify multiple match functions")
-
-
-class MultiMatchStreamSubject(object):
-
- def __init__(self, stream, match_fns, timeout):
- self._stream = stream
- self._match_fns = match_fns
- self._timeout = timeout
-
- def inAnyOrder(self):
- NOT_FOR_YOU_assert_all_events_occur(self._stream, self._match_fns, order_matters=False, timeout=self._timeout)
- return EventStreamContinuationSubject(self._stream)
-
- def inOrder(self):
- NOT_FOR_YOU_assert_all_events_occur(self._stream, self._match_fns, order_matters=True, timeout=self._timeout)
- return EventStreamContinuationSubject(self._stream)
-
-
-class EventStreamContinuationSubject(ObjectSubject):
-
- def __init__(self, value):
- super().__init__(value)
-
- def then(self, *match_fns, at_least_times=1, timeout=DEFAULT_TIMEOUT):
- if len(match_fns) == 0:
- raise signals.TestFailure("Must specify a match function")
- elif len(match_fns) == 1:
- NOT_FOR_YOU_assert_event_occurs(self._value, match_fns[0], at_least_times=at_least_times, timeout=timeout)
- return EventStreamContinuationSubject(self._value)
- else:
- return MultiMatchStreamSubject(self._value, match_fns, timeout)
-
- def thenNone(self, *match_fns, timeout):
- if len(match_fns) == 0:
- NOT_FOR_YOU_assert_none(self._value, timeout=timeout)
- return EventStreamContinuationSubject(self._value)
- elif len(match_fns) == 1:
- NOT_FOR_YOU_assert_none_matching(self._value, match_fns[0], timeout=timeout)
- return EventStreamContinuationSubject(self._value)
- else:
- raise signals.TestFailure("Cannot specify multiple match functions")
-
-
-class BooleanSubject(ObjectSubject):
-
- def __init__(self, value):
- super().__init__(value)
-
- def isTrue(self):
- assert_true(self._value, "")
-
- def isFalse(self):
- assert_false(self._value, "")
-
-
-class TimeDeltaSubject(ObjectSubject):
-
- def __init__(self, value):
- super().__init__(value)
-
- def isWithin(self, time_bound):
- assert_true(self._value < time_bound, "")
-
-
-def assertThat(subject):
- if type(subject) is bool:
- return BooleanSubject(subject)
- elif isinstance(subject, IEventStream):
- return EventStreamSubject(subject)
- elif isinstance(subject, timedelta):
- return TimeDeltaSubject(subject)
- else:
- return ObjectSubject(subject)
diff --git a/system/blueberry/tests/gd/devices_config.yaml b/system/blueberry/tests/gd/devices_config.yaml
deleted file mode 100644
index 2f8bbc82e0..0000000000
--- a/system/blueberry/tests/gd/devices_config.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-_description: Bluetooth cert testing
-TestBeds:
- - Name: AndroidDeviceCert
- Controllers:
- GdDevice:
- - grpc_port: '8898'
- grpc_root_server_port: '8896'
- signal_port: '8894'
- label: cert
- serial_number: 'CERT'
- name: Cert Device
- cmd:
- - "adb"
- - "-s"
- - "$(serial_number)"
- - "shell"
- - "ASAN_OPTIONS=detect_container_overflow=0"
- - "/system/bin/bluetooth_stack_with_facade"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--btsnoop=/data/misc/bluetooth/logs/btsnoop_hci.log"
- - "--btsnooz=/data/misc/bluetooth/logs/btsnooz_hci.log"
- - "--btconfig=/data/misc/bluedroid/bt_config.conf"
- - "--signal-port=$(signal_port)"
- - grpc_port: '8899'
- grpc_root_server_port: '8897'
- signal_port: '8895'
- label: dut
- serial_number: 'DUT'
- name: DUT Device
- cmd:
- - "adb"
- - "-s"
- - "$(serial_number)"
- - "shell"
- - "ASAN_OPTIONS=detect_container_overflow=0"
- - "/system/bin/bluetooth_stack_with_facade"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--btsnoop=/data/misc/bluetooth/logs/btsnoop_hci.log"
- - "--btsnooz=/data/misc/bluetooth/logs/btsnooz_hci.log"
- - "--btconfig=/data/misc/bluedroid/bt_config.conf"
- - "--signal-port=$(signal_port)"
-logpath: "/tmp/logs" \ No newline at end of file
diff --git a/system/blueberry/tests/gd/gd_all_tests.py b/system/blueberry/tests/gd/gd_all_tests.py
deleted file mode 100644
index 69fed0b1f0..0000000000
--- a/system/blueberry/tests/gd/gd_all_tests.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-from blueberry.tests.gd.cert.cert_self_test import CertSelfTest
-from blueberry.tests.gd.hal.simple_hal_test import SimpleHalTest
-from blueberry.tests.gd.hci.acl_manager_test import AclManagerTest
-from blueberry.tests.gd.hci.controller_test import ControllerTest
-from blueberry.tests.gd.hci.direct_hci_test import DirectHciTest
-from blueberry.tests.gd.hci.le_acl_manager_test import LeAclManagerTest
-from blueberry.tests.gd.hci.le_advertising_manager_test import LeAdvertisingManagerTest
-from blueberry.tests.gd.hci.le_scanning_manager_test import LeScanningManagerTest
-from blueberry.tests.gd.hci.le_scanning_with_security_test import LeScanningWithSecurityTest
-from blueberry.tests.gd.iso.le_iso_test import LeIsoTest
-from blueberry.tests.gd.shim.shim_test import ShimTest
-from blueberry.tests.gd.shim.stack_test import StackTest
-
-from mobly import suite_runner
-
-ALL_TESTS = {
- CertSelfTest, SimpleHalTest, AclManagerTest, ControllerTest, DirectHciTest, LeAclManagerTest,
- LeAdvertisingManagerTest, LeScanningManagerTest, LeScanningWithSecurityTest, LeIsoTest,
- ShimTest, StackTest
-}
-
-DISABLED_TESTS = set()
-
-ENABLED_TESTS = list(ALL_TESTS - DISABLED_TESTS)
-
-if __name__ == '__main__':
- suite_runner.run_suite(ENABLED_TESTS)
diff --git a/system/blueberry/tests/gd/gd_postsubmit_tests.py b/system/blueberry/tests/gd/gd_postsubmit_tests.py
deleted file mode 100644
index 41cd09ee56..0000000000
--- a/system/blueberry/tests/gd/gd_postsubmit_tests.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-from blueberry.tests.gd.gd_all_tests import ALL_TESTS
-
-from mobly import suite_runner
-
-DISABLED_TESTS = set()
-
-POSTSUBMIT_TESTS = list(ALL_TESTS - DISABLED_TESTS)
-
-if __name__ == '__main__':
- suite_runner.run_suite(POSTSUBMIT_TESTS)
diff --git a/system/blueberry/tests/gd/gd_presubmit_tests.py b/system/blueberry/tests/gd/gd_presubmit_tests.py
deleted file mode 100644
index 633d637c23..0000000000
--- a/system/blueberry/tests/gd/gd_presubmit_tests.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-from blueberry.tests.gd.gd_all_tests import ALL_TESTS
-
-from mobly import suite_runner
-
-# TODO(b/194723246): Investigate failures to re-activate the test class.
-from blueberry.tests.gd.hci.le_scanning_manager_test import LeScanningManagerTest
-
-DISABLED_TESTS = {LeScanningManagerTest}
-
-PRESUBMIT_TESTS = list(ALL_TESTS - DISABLED_TESTS)
-
-if __name__ == '__main__':
- suite_runner.run_suite(PRESUBMIT_TESTS)
diff --git a/system/blueberry/tests/gd/gd_test_runner.py b/system/blueberry/tests/gd/gd_test_runner.py
deleted file mode 100644
index cc2a1d2336..0000000000
--- a/system/blueberry/tests/gd/gd_test_runner.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-from blueberry.tests.gd.gd_all_tests import ALL_TESTS
-from blueberry.tests.gd.gd_presubmit_tests import PRESUBMIT_TESTS
-from blueberry.tests.gd.gd_postsubmit_tests import POSTSUBMIT_TESTS
-
-from mobly import suite_runner
-import sys
-import argparse
-import pathlib
-
-DISABLED_TESTS = set()
-
-ENABLED_TESTS = list(ALL_TESTS - DISABLED_TESTS)
-
-
-def main():
- """
- Local test runner that allows to specify list of tests to and customize
- test config file location
- """
- parser = argparse.ArgumentParser(description="Run local GD cert tests.")
- parser.add_argument(
- '-c', '--config', type=str, required=True, metavar='<PATH>', help='Path to the test configuration file.')
- parser.add_argument(
- '--tests',
- '--test_case',
- nargs='+',
- type=str,
- metavar='[ClassA[.test_a] ClassB[.test_b] ...]',
- help='A list of test classes and optional tests to execute.')
- parser.add_argument("--all_tests", "-A", type=bool, dest="all_tests", default=False, nargs="?")
- parser.add_argument("--presubmit", type=bool, dest="presubmit", default=False, nargs="?")
- parser.add_argument("--postsubmit", type=bool, dest="postsubmit", default=False, nargs="?")
- args = parser.parse_args()
- test_list = ALL_TESTS
- if args.all_tests:
- test_list = ALL_TESTS
- elif args.presubmit:
- test_list = PRESUBMIT_TESTS
- elif args.postsubmit:
- test_list = POSTSUBMIT_TESTS
- # Do not pass this layer's cmd line argument to next layer
- argv = ["--config", args.config]
- if args.tests:
- argv.append("--tests")
- for test in args.tests:
- argv.append(test)
-
- suite_runner.run_suite(test_list, argv=argv)
-
-
-if __name__ == "__main__":
- main()
diff --git a/system/blueberry/tests/gd/hal/simple_hal_test.py b/system/blueberry/tests/gd/hal/simple_hal_test.py
deleted file mode 100644
index 0a9fef101c..0000000000
--- a/system/blueberry/tests/gd/hal/simple_hal_test.py
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert.py_hal import PyHal
-from blueberry.tests.gd.cert.matchers import HciMatchers
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.utils import bluetooth
-from mobly import test_runner
-import hci_packets as hci
-
-_GRPC_TIMEOUT = 10
-
-
-class SimpleHalTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HAL', cert_module='HAL')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.setup_test(self)
- self.dut_hal = PyHal(self.dut)
- self.cert_hal = PyHal(self.cert)
-
- self.dut_hal.reset()
- self.cert_hal.reset()
-
- def teardown_test(self):
- self.dut_hal.close()
- self.cert_hal.close()
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
- def test_stream_events(self):
- self.dut_hal.send_hci_command(
- hci.LeAddDeviceToFilterAcceptList(address_type=hci.FilterAcceptListAddressType.RANDOM,
- address=bluetooth.Address('0C:05:04:03:02:01')))
- assertThat(self.dut_hal.get_hci_event_stream()).emits(
- HciMatchers.Exactly(
- hci.LeAddDeviceToFilterAcceptListComplete(num_hci_command_packets=1, status=hci.ErrorCode.SUCCESS)))
-
- def test_loopback_hci_command(self):
- self.dut_hal.send_hci_command(hci.WriteLoopbackMode(loopback_mode=hci.LoopbackMode.ENABLE_LOCAL))
-
- command = hci.LeAddDeviceToFilterAcceptList(address_type=hci.FilterAcceptListAddressType.RANDOM,
- address=bluetooth.Address('0C:05:04:03:02:01'))
- self.dut_hal.send_hci_command(command)
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(HciMatchers.LoopbackOf(command.serialize()))
-
- def test_inquiry_from_dut(self):
- self.cert_hal.send_hci_command(hci.WriteScanEnable(scan_enable=hci.ScanEnable.INQUIRY_AND_PAGE_SCAN))
-
- self.dut_hal.send_hci_command(hci.Inquiry(lap=hci.Lap(lap=0x33), inquiry_length=0x30, num_responses=0xff))
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(lambda packet: b'\x02\x0f' in packet.payload
- # Expecting an HCI Event (code 0x02, length 0x0f)
- )
-
- def test_le_ad_scan_cert_advertises(self):
- self.dut_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- self.dut_hal.unmask_le_event(hci.SubeventCode.EXTENDED_ADVERTISING_REPORT)
- self.dut_hal.set_random_le_address('0D:05:04:03:02:01')
-
- self.dut_hal.set_scan_parameters()
- self.dut_hal.start_scanning()
-
- advertisement = self.cert_hal.create_advertisement(0,
- '0C:05:04:03:02:01',
- min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1',
- tx_power=0x7f,
- sid=1)
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- assertThat(self.dut_hal.get_hci_event_stream()).emits(lambda packet: b'Im_A_Cert' in packet.payload)
-
- advertisement.stop()
-
- self.dut_hal.stop_scanning()
-
- def test_le_connection_dut_advertises(self):
- self.cert_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- self.cert_hal.set_random_le_address('0C:05:04:03:02:01')
- self.cert_hal.initiate_le_connection('0D:05:04:03:02:01')
-
- # DUT Advertises
- self.dut_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- advertisement = self.dut_hal.create_advertisement(0, '0D:05:04:03:02:01')
- advertisement.set_data(b'Im_The_DUT')
- advertisement.set_scan_response(b'Im_The_D')
- advertisement.start()
-
- cert_acl = self.cert_hal.complete_le_connection()
- dut_acl = self.dut_hal.complete_le_connection()
-
- dut_acl.send_first(b'Just SomeAclData')
- cert_acl.send_first(b'Just SomeMoreAclData')
-
- assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
- assertThat(self.dut_hal.get_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
-
- def test_le_filter_accept_list_connection_cert_advertises(self):
- self.dut_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- self.dut_hal.set_random_le_address('0D:05:04:03:02:01')
- self.dut_hal.add_to_filter_accept_list('0C:05:04:03:02:01')
- self.dut_hal.initiate_le_connection_by_filter_accept_list('BA:D5:A4:A3:A2:A1')
-
- self.cert_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- advertisement = self.cert_hal.create_advertisement(1,
- '0C:05:04:03:02:01',
- min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1',
- tx_power=0x7F,
- sid=0)
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- assertThat(self.cert_hal.get_hci_event_stream()).emits(HciMatchers.LeConnectionComplete())
- assertThat(self.dut_hal.get_hci_event_stream()).emits(HciMatchers.LeConnectionComplete())
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/acl_manager_test.py b/system/blueberry/tests/gd/hci/acl_manager_test.py
deleted file mode 100644
index b01e0265e3..0000000000
--- a/system/blueberry/tests/gd/hci/acl_manager_test.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.tests.gd.cert.py_hci import PyHci
-from blueberry.tests.gd.cert.py_acl_manager import PyAclManager
-from blueberry.tests.gd.cert.truth import assertThat
-from datetime import timedelta
-from blueberry.facade.neighbor import facade_pb2 as neighbor_facade
-from mobly import test_runner
-import hci_packets as hci
-
-
-class AclManagerTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
-
- # todo: move into GdBaseTestClass, based on modules inited
- def setup_test(self):
- gd_base_test.GdBaseTestClass.setup_test(self)
- self.cert_hci = PyHci(self.cert, acl_streaming=True)
- self.dut_acl_manager = PyAclManager(self.dut)
-
- def teardown_test(self):
- self.cert_hci.close()
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
- def test_dut_connects(self):
- self.cert_hci.enable_inquiry_and_page_scan()
- cert_address = self.cert_hci.read_own_address()
-
- self.dut_acl_manager.initiate_connection(repr(cert_address))
- cert_acl = self.cert_hci.accept_connection()
- with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
- cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
- dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
-
- assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- def test_cert_connects(self):
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
-
- self.dut_acl_manager.listen_for_an_incoming_connection()
- self.cert_hci.initiate_connection(dut_address)
- with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
- cert_acl = self.cert_hci.complete_connection()
-
- dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
-
- cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
-
- assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- def test_reject_broadcast(self):
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
-
- self.dut_acl_manager.listen_for_an_incoming_connection()
- self.cert_hci.initiate_connection(dut_address)
- with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
- cert_acl = self.cert_hci.complete_connection()
-
- cert_acl.send(hci.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE,
- hci.BroadcastFlag.ACTIVE_PERIPHERAL_BROADCAST,
- b'\x26\x00\x07\x00This is a Broadcast from the Cert')
- assertThat(dut_acl).emitsNone(timeout=timedelta(seconds=0.5))
-
- cert_acl.send(hci.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE, hci.BroadcastFlag.POINT_TO_POINT,
- b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- def test_cert_connects_disconnects(self):
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
- self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
-
- self.dut_acl_manager.listen_for_an_incoming_connection()
- self.cert_hci.initiate_connection(dut_address)
- with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
- cert_acl = self.cert_hci.complete_connection()
-
- dut_acl.send(b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')
-
- cert_acl.send_first(b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
-
- assertThat(cert_acl).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- dut_acl.disconnect(hci.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION)
- dut_acl.wait_for_disconnection_complete()
-
- def test_recombination_l2cap_packet(self):
- self.cert_hci.enable_inquiry_and_page_scan()
- cert_address = self.cert_hci.read_own_address()
-
- self.dut_acl_manager.initiate_connection(repr(cert_address))
- cert_acl = self.cert_hci.accept_connection()
- with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
- cert_acl.send_first(b'\x06\x00\x07\x00Hello')
- cert_acl.send_continuing(b'!')
- cert_acl.send_first(b'\xe8\x03\x07\x00' + b'Hello' * 200)
-
- assertThat(dut_acl).emits(lambda packet: b'Hello!' in packet.payload,
- lambda packet: b'Hello' * 200 in packet.payload).inOrder()
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/controller_test.py b/system/blueberry/tests/gd/hci/controller_test.py
deleted file mode 100644
index 3177695110..0000000000
--- a/system/blueberry/tests/gd/hci/controller_test.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-import time
-
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.tests.gd.cert.truth import assertThat
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.facade.hci import controller_facade_pb2 as controller_facade
-from mobly import test_runner
-import hci_packets as hci
-
-
-class ControllerTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
-
- def test_get_addresses(self):
- cert_address = self.cert.hci_controller.GetMacAddressSimple()
- dut_address = self.dut.hci_controller.GetMacAddressSimple()
-
- assertThat(cert_address).isNotEqualTo(dut_address)
- time.sleep(1) # This shouldn't be needed b/149120542
-
- def test_write_local_name(self):
- self.dut.hci_controller.WriteLocalName(controller_facade.NameMsg(name=b'ImTheDUT'))
- self.cert.hci_controller.WriteLocalName(controller_facade.NameMsg(name=b'ImTheCert'))
- cert_name = self.cert.hci_controller.GetLocalNameSimple()
- dut_name = self.dut.hci_controller.GetLocalNameSimple()
-
- assertThat(dut_name).isEqualTo(b'ImTheDUT')
- assertThat(cert_name).isEqualTo(b'ImTheCert')
-
- def test_extended_advertising_support(self):
- extended_advertising_supported = self.dut.hci_controller.SupportsBleExtendedAdvertising(empty_proto.Empty())
- if extended_advertising_supported.supported:
- number_of_sets = self.dut.hci_controller.GetLeNumberOfSupportedAdvertisingSets(empty_proto.Empty())
- assertThat(number_of_sets.value).isGreaterThan(5) # Android threshold for CTS
- supported = self.dut.hci_controller.IsSupportedCommand(
- controller_facade.OpCodeMsg(op_code=int(hci.OpCode.LE_SET_EXTENDED_ADVERTISING_PARAMETERS)))
- assertThat(supported.supported).isEqualTo(True)
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/direct_hci_test.py b/system/blueberry/tests/gd/hci/direct_hci_test.py
deleted file mode 100644
index b3f6309e3d..0000000000
--- a/system/blueberry/tests/gd/hci/direct_hci_test.py
+++ /dev/null
@@ -1,324 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-import logging
-
-from blueberry.tests.gd.cert.captures import HalCaptures, HciCaptures
-from blueberry.tests.gd.cert.matchers import HciMatchers
-from blueberry.tests.gd.cert.py_hal import PyHal
-from blueberry.tests.gd.cert.py_hci import PyHci
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.facade import common_pb2 as common
-from mobly import test_runner
-
-import hci_packets as hci
-from blueberry.utils import bluetooth
-
-
-class DirectHciTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI', cert_module='HAL')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.setup_test(self)
- self.dut_hci = PyHci(self.dut, acl_streaming=True)
- self.cert_hal = PyHal(self.cert)
- self.cert_hal.send_hci_command(hci.Reset())
-
- def teardown_test(self):
- self.dut_hci.close()
- self.cert_hal.close()
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
- def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
- acl = hci.Acl(handle=handle, packet_boundary_flag=pb_flag, broadcast_flag=b_flag, payload=data)
- self.dut.hci.SendAcl(common.Data(payload=acl.serialize()))
-
- def test_local_hci_cmd_and_event(self):
- # Loopback mode responds with ACL and SCO connection complete
- self.dut_hci.register_for_events(hci.EventCode.LOOPBACK_COMMAND)
- self.dut_hci.send_command(hci.WriteLoopbackMode(loopback_mode=hci.LoopbackMode.ENABLE_LOCAL))
-
- self.dut_hci.send_command(hci.ReadLocalName())
- assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.LoopbackOf(hci.ReadLocalName().serialize()))
-
- def test_inquiry_from_dut(self):
- self.dut_hci.register_for_events(hci.EventCode.INQUIRY_RESULT)
-
- self.cert_hal.enable_inquiry_and_page_scan()
- self.dut_hci.send_command(hci.Inquiry(lap=hci.Lap(lap=0x33), inquiry_length=0x30, num_responses=0xff))
- assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.EventWithCode(hci.EventCode.INQUIRY_RESULT))
-
- def test_le_ad_scan_cert_advertises(self):
- self.dut_hci.register_for_le_events(hci.SubeventCode.EXTENDED_ADVERTISING_REPORT,
- hci.SubeventCode.ADVERTISING_REPORT)
-
- # DUT Scans
- self.dut_hci.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0D:05:04:03:02:01')))
-
- self.dut_hci.send_command(
- hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL,
- scanning_phys=1,
- parameters=[
- hci.PhyScanParameters(le_scan_type=hci.LeScanType.ACTIVE,
- le_scan_interval=6553,
- le_scan_window=6553)
- ]))
-
- self.dut_hci.send_command(
- hci.LeSetExtendedScanEnable(enable=hci.Enable.ENABLED,
- filter_duplicates=hci.FilterDuplicates.DISABLED,
- duration=0,
- period=0))
-
- # CERT Advertises
- advertising_handle = 0
- self.cert_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingParametersLegacy(
- advertising_handle=advertising_handle,
- legacy_advertising_event_properties=hci.LegacyAdvertisingEventProperties.ADV_IND,
- primary_advertising_interval_min=512,
- primary_advertising_interval_max=768,
- primary_advertising_channel_map=7,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- peer_address=bluetooth.Address('A6:A5:A4:A3:A2:A1'),
- advertising_filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES,
- advertising_tx_power=0xF7,
- advertising_sid=1,
- scan_request_notification_enable=hci.Enable.DISABLED))
-
- self.cert_hal.send_hci_command(
- hci.LeSetAdvertisingSetRandomAddress(advertising_handle=advertising_handle,
- random_address=bluetooth.Address('0C:05:04:03:02:01')))
-
- self.cert_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingData(
- advertising_handle=advertising_handle,
- operation=hci.Operation.COMPLETE_ADVERTISEMENT,
- fragment_preference=hci.FragmentPreference.CONTROLLER_SHOULD_NOT,
- advertising_data=[hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(b'Im_A_Cert'))]))
-
- self.cert_hal.send_hci_command(
- hci.LeSetExtendedScanResponseData(
- advertising_handle=advertising_handle,
- operation=hci.Operation.COMPLETE_ADVERTISEMENT,
- fragment_preference=hci.FragmentPreference.CONTROLLER_SHOULD_NOT,
- scan_response_data=[hci.GapData(data_type=hci.GapDataType.SHORTENED_LOCAL_NAME, data=list(b'Im_A_C'))]))
-
- self.cert_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingEnable(enable=hci.Enable.ENABLED,
- enabled_sets=[
- hci.EnabledSet(advertising_handle=advertising_handle,
- duration=0,
- max_extended_advertising_events=0)
- ]))
-
- assertThat(self.dut_hci.get_le_event_stream()).emits(lambda packet: b'Im_A_Cert' in packet.payload)
-
- self.cert_hal.send_hci_command(
- hci.LeSetExtendedAdvertisingEnable(enable=hci.Enable.DISABLED,
- enabled_sets=[
- hci.EnabledSet(advertising_handle=advertising_handle,
- duration=0,
- max_extended_advertising_events=0)
- ]))
-
- self.dut_hci.send_command(hci.LeSetExtendedScanEnable(enable=hci.Enable.DISABLED))
-
- def _verify_le_connection_complete(self):
- cert_conn_complete_capture = HalCaptures.LeConnectionCompleteCapture()
- assertThat(self.cert_hal.get_hci_event_stream()).emits(cert_conn_complete_capture)
- cert_handle = cert_conn_complete_capture.get().connection_handle
-
- dut_conn_complete_capture = HciCaptures.LeConnectionCompleteCapture()
- assertThat(self.dut_hci.get_le_event_stream()).emits(dut_conn_complete_capture)
- dut_handle = dut_conn_complete_capture.get().connection_handle
-
- return (dut_handle, cert_handle)
-
- @staticmethod
- def _create_phy_scan_params():
- return hci.LeCreateConnPhyScanParameters(scan_interval=0x60,
- scan_window=0x30,
- conn_interval_min=0x18,
- conn_interval_max=0x28,
- conn_latency=0,
- supervision_timeout=0x1f4,
- min_ce_length=0,
- max_ce_length=0)
-
- def test_le_connection_dut_advertises(self):
- self.dut_hci.register_for_le_events(hci.SubeventCode.CONNECTION_COMPLETE,
- hci.SubeventCode.ADVERTISING_SET_TERMINATED,
- hci.SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
- # Cert Connects
- self.cert_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- self.cert_hal.send_hci_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0C:05:04:03:02:01')))
- self.cert_hal.send_hci_command(
- hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_PEER_ADDRESS,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- peer_address_type=hci.AddressType.RANDOM_DEVICE_ADDRESS,
- peer_address=bluetooth.Address('0D:05:04:03:02:01'),
- initiating_phys=1,
- phy_scan_parameters=[self._create_phy_scan_params()]))
-
- advertisement = self.dut_hci.create_advertisement(0, '0D:05:04:03:02:01')
- advertisement.set_data(b'Im_The_DUT')
- advertisement.set_scan_response(b'Im_The_D')
- advertisement.start()
-
- (dut_handle, cert_handle) = self._verify_le_connection_complete()
-
- self.dut_hci.send_command(hci.LeReadRemoteFeatures(connection_handle=dut_handle))
- assertThat(self.dut_hci.get_le_event_stream()).emits(lambda packet: packet.payload[0] == int(
- hci.EventCode.LE_META_EVENT) and packet.payload[2] == int(hci.SubeventCode.READ_REMOTE_FEATURES_COMPLETE))
-
- # Send ACL Data
- self.enqueue_acl_data(dut_handle, hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci.BroadcastFlag.POINT_TO_POINT, bytes(b'Just SomeAclData'))
- self.cert_hal.send_acl_first(cert_handle, bytes(b'Just SomeMoreAclData'))
-
- assertThat(self.cert_hal.get_acl_stream()).emits(
- lambda packet: logging.debug(packet.payload) or b'SomeAclData' in packet.payload)
- assertThat(self.dut_hci.get_raw_acl_stream()).emits(
- lambda packet: logging.debug(packet.payload) or b'SomeMoreAclData' in packet.payload)
-
- def test_le_filter_accept_list_connection_cert_advertises(self):
- # DUT Connects
- self.dut_hci.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0D:05:04:03:02:01')))
- self.dut_hci.send_command(
- hci.LeAddDeviceToFilterAcceptList(address_type=hci.FilterAcceptListAddressType.RANDOM,
- address=bluetooth.Address('0C:05:04:03:02:01')))
- self.dut_hci.send_command(
- hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_FILTER_ACCEPT_LIST,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- initiating_phys=1,
- phy_scan_parameters=[self._create_phy_scan_params()]))
-
- self.cert_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- advertisement = self.cert_hal.create_advertisement(1,
- '0C:05:04:03:02:01',
- min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1',
- tx_power=0x7f,
- sid=0)
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- # LeConnectionComplete
- self._verify_le_connection_complete()
-
- def test_le_filter_accept_list_connection_cert_advertises_legacy(self):
- # DUT Connects
- self.dut_hci.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0D:05:04:03:02:01')))
- self.dut_hci.send_command(
- hci.LeAddDeviceToFilterAcceptList(address_type=hci.FilterAcceptListAddressType.RANDOM,
- address=bluetooth.Address('0C:05:04:03:02:01')))
- self.dut_hci.send_command(
- hci.LeExtendedCreateConnection(initiator_filter_policy=hci.InitiatorFilterPolicy.USE_FILTER_ACCEPT_LIST,
- own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- initiating_phys=1,
- phy_scan_parameters=[self._create_phy_scan_params()]))
-
- self.cert_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- self.cert_hal.send_hci_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0C:05:04:03:02:01')))
-
- advertisement = self.cert_hal.create_legacy_advertisement(min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1')
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- # LeConnectionComplete
- self._verify_le_connection_complete()
-
- def test_le_ad_scan_cert_advertises_legacy(self):
- self.dut_hci.register_for_le_events(hci.SubeventCode.EXTENDED_ADVERTISING_REPORT,
- hci.SubeventCode.ADVERTISING_REPORT)
-
- # DUT Scans
- self.dut_hci.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0D:05:04:03:02:01')))
-
- self.dut_hci.send_command(
- hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL,
- scanning_phys=1,
- parameters=[
- hci.PhyScanParameters(le_scan_type=hci.LeScanType.ACTIVE,
- le_scan_interval=6553,
- le_scan_window=6553)
- ]))
-
- self.dut_hci.send_command(
- hci.LeSetExtendedScanEnable(enable=hci.Enable.ENABLED,
- filter_duplicates=hci.FilterDuplicates.DISABLED,
- duration=0,
- period=0))
-
- self.cert_hal.unmask_event(hci.EventCode.LE_META_EVENT)
- self.cert_hal.send_hci_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0C:05:04:03:02:01')))
-
- advertisement = self.cert_hal.create_legacy_advertisement(min_interval=512,
- max_interval=768,
- peer_address='A6:A5:A4:A3:A2:A1')
- advertisement.set_data(b'Im_A_Cert')
- advertisement.start()
-
- assertThat(self.dut_hci.get_le_event_stream()).emits(
- HciMatchers.LeAdvertisement(address='0C:05:04:03:02:01', data=b'Im_A_Cert'))
-
- def test_connection_dut_connects(self):
- self.dut_hci.send_command(hci.WritePageTimeout(page_timeout=0x4000))
-
- self.cert_hal.enable_inquiry_and_page_scan()
- address = self.cert_hal.read_own_address()
-
- self.dut_hci.initiate_connection(address)
- cert_acl = self.cert_hal.accept_connection()
- dut_acl = self.dut_hci.complete_connection()
-
- # Send ACL Data
- dut_acl.send_first(b'Just SomeAclData')
- cert_acl.send_first(b'Just SomeMoreAclData')
-
- assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
- assertThat(self.dut_hci.get_raw_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
-
- def test_connection_cert_connects(self):
- self.cert_hal.send_hci_command(hci.WritePageTimeout(page_timeout=0x4000))
-
- self.dut_hci.enable_inquiry_and_page_scan()
- address = self.dut_hci.read_own_address()
-
- self.cert_hal.initiate_connection(address)
- dut_acl = self.dut_hci.accept_connection()
- cert_acl = self.cert_hal.complete_connection()
-
- # Send ACL Data
- dut_acl.send_first(b'This is just SomeAclData')
- cert_acl.send_first(b'This is just SomeMoreAclData')
-
- assertThat(self.cert_hal.get_acl_stream()).emits(lambda packet: b'SomeAclData' in packet.payload)
- assertThat(self.dut_hci.get_raw_acl_stream()).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/le_acl_manager_test.py b/system/blueberry/tests/gd/hci/le_acl_manager_test.py
deleted file mode 100644
index 51c01a5a1b..0000000000
--- a/system/blueberry/tests/gd/hci/le_acl_manager_test.py
+++ /dev/null
@@ -1,438 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert.py_hci import PyHci, PyHciAdvertisement
-from blueberry.tests.gd.cert.py_le_acl_manager import PyLeAclManager
-from blueberry.facade import common_pb2 as common
-from blueberry.facade.hci import le_acl_manager_facade_pb2 as le_acl_manager_facade
-from blueberry.facade.hci import le_advertising_manager_facade_pb2 as le_advertising_facade
-from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from blueberry.facade.hci import hci_facade_pb2 as hci_facade
-from mobly import test_runner
-import hci_packets as hci
-
-
-class LeAclManagerTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.setup_test(self)
- self.cert_hci = PyHci(self.cert, acl_streaming=True)
- self.dut_le_acl_manager = PyLeAclManager(self.dut)
- self.cert_public_address = self.cert_hci.read_own_address()
- self.dut_public_address = self.dut.hci_controller.GetMacAddressSimple().decode("utf-8")
- self.dut_random_address = 'd0:05:04:03:02:01'
- self.cert_random_address = 'c0:05:04:03:02:01'
-
- def teardown_test(self):
- safeClose(self.dut_le_acl_manager)
- self.cert_hci.close()
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
- def set_privacy_policy_static(self):
- private_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.dut_random_address, "utf-8")),
- type=common.RANDOM_DEVICE_ADDRESS))
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(private_policy)
-
- def register_for_event(self, event_code):
- msg = hci_facade.EventRequest(code=int(event_code))
- self.cert.hci.RequestEvent(msg)
-
- def register_for_le_event(self, event_code):
- msg = hci_facade.EventRequest(code=int(event_code))
- self.cert.hci.RequestLeSubevent(msg)
-
- def enqueue_hci_command(self, command):
- cmd_bytes = bytes(command.serialize())
- cmd = common.Data(payload=cmd_bytes)
- self.cert.hci.SendCommand(cmd)
-
- def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
- acl = hci.Acl(handle=handle, packet_boundary_flag=pb_flag, broadcast_flag=b_flag, payload=data)
- self.cert.hci.SendAcl(common.Data(payload=acl.serialize()))
-
- def dut_connects(self):
- # Cert Advertises
- advertising_handle = 0
- py_hci_adv = PyHciAdvertisement(advertising_handle, self.cert_hci)
-
- self.cert_hci.create_advertisement(
- advertising_handle,
- self.cert_random_address,
- hci.LegacyAdvertisingEventProperties.ADV_IND,
- )
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
- remote_addr=common.BluetoothAddressWithType(address=common.BluetoothAddress(
- address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)))
-
- cert_le_acl = self.cert_hci.incoming_le_connection()
- return dut_le_acl, cert_le_acl
-
- def cert_advertises_resolvable(self):
- self.cert_hci.add_device_to_resolving_list(hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- self.dut_public_address,
- b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
- b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f')
-
- # Cert Advertises
- advertising_handle = 0
- py_hci_adv = PyHciAdvertisement(advertising_handle, self.cert_hci)
-
- self.cert_hci.create_advertisement(advertising_handle,
- self.cert_random_address,
- hci.LegacyAdvertisingEventProperties.ADV_IND,
- own_address_type=hci.OwnAddressType.RESOLVABLE_OR_PUBLIC_ADDRESS,
- peer_address=self.dut_public_address,
- peer_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS)
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- def dut_connects_cert_resolvable(self):
- self.dut.hci_le_acl_manager.AddDeviceToResolvingList(
- le_acl_manager_facade.IrkMsg(
- peer=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=repr(self.cert_public_address).encode('utf-8')),
- type=int(hci.AddressType.PUBLIC_DEVICE_ADDRESS)),
- peer_irk=b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f',
- local_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
- ))
-
- dut_le_acl = self.dut_le_acl_manager.connect_to_remote(
- remote_addr=common.BluetoothAddressWithType(address=common.BluetoothAddress(
- address=repr(self.cert_public_address).encode('utf-8')),
- type=int(hci.AddressType.PUBLIC_DEVICE_ADDRESS)))
-
- cert_le_acl = self.cert_hci.incoming_le_connection()
- return dut_le_acl, cert_le_acl
-
- def send_receive_and_check(self, dut_le_acl, cert_le_acl):
- self.enqueue_acl_data(cert_le_acl.handle, hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci.BroadcastFlag.POINT_TO_POINT, bytes(b'\x19\x00\x07\x00SomeAclData from the Cert'))
-
- dut_le_acl.send(b'\x1C\x00\x07\x00SomeMoreAclData from the DUT')
- assertThat(cert_le_acl.our_acl_stream).emits(lambda packet: b'SomeMoreAclData' in packet.payload)
- assertThat(dut_le_acl).emits(lambda packet: b'SomeAclData' in packet.payload)
-
- def test_dut_connects(self):
- self.set_privacy_policy_static()
- dut_le_acl, cert_le_acl = self.dut_connects()
-
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isEqualTo(self.dut_random_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_dut_connects_resolvable_address(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_RESOLVABLE_ADDRESS,
- rotation_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
- minimum_rotation_time=7 * 60 * 1000,
- maximum_rotation_time=15 * 60 * 1000)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- dut_le_acl, cert_le_acl = self.dut_connects()
-
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_public_address)
- assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_random_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_dut_connects_resolvable_address_public(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_RESOLVABLE_ADDRESS,
- rotation_irk=b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f',
- minimum_rotation_time=7 * 60 * 1000,
- maximum_rotation_time=15 * 60 * 1000)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- self.cert_advertises_resolvable()
- dut_le_acl, cert_le_acl = self.dut_connects_cert_resolvable()
-
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_public_address)
- assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_random_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(repr(self.cert_public_address))
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.PUBLIC_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_dut_connects_non_resolvable_address(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_NON_RESOLVABLE_ADDRESS,
- rotation_irk=b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f',
- minimum_rotation_time=8 * 60 * 1000,
- maximum_rotation_time=14 * 60 * 1000)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- dut_le_acl, cert_le_acl = self.dut_connects()
-
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_public_address)
- assertThat(cert_le_acl.peer).isNotEqualTo(self.dut_random_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_dut_connects_public_address(self):
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
- le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
- dut_le_acl, cert_le_acl = self.dut_connects()
-
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isEqualTo(self.dut_public_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.PUBLIC_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_dut_connects_public_address_cancelled(self):
- # TODO (Add cancel)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(
- le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS))
- dut_le_acl, cert_le_acl = self.dut_connects()
-
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isEqualTo(self.dut_public_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.PUBLIC_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_cert_connects(self):
- self.set_privacy_policy_static()
- self.dut_le_acl_manager.listen_for_incoming_connections()
-
- # DUT Advertises
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- peer_address_type=common.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
- peer_address=common.BluetoothAddress(address=bytes(b'A6:A5:A4:A3:A2:A1')),
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
-
- # Cert Connects
- self.cert_hci.set_random_le_address(self.cert_random_address)
- self.cert_hci.initiate_le_connection(self.dut_random_address)
-
- # Cert gets ConnectionComplete with a handle and sends ACL data
- cert_le_acl = self.cert_hci.incoming_le_connection()
-
- cert_le_acl.send(hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE, hci.BroadcastFlag.POINT_TO_POINT,
- b'\x19\x00\x07\x00SomeAclData from the Cert')
-
- # DUT gets a connection complete event and sends and receives
- dut_le_acl = self.dut_le_acl_manager.complete_incoming_connection()
- assertThat(cert_le_acl.handle).isNotNone()
- assertThat(cert_le_acl.peer).isEqualTo(self.dut_random_address)
- assertThat(cert_le_acl.peer_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- assertThat(dut_le_acl.handle).isNotNone()
- assertThat(dut_le_acl.remote_address).isEqualTo(self.cert_random_address)
- assertThat(dut_le_acl.remote_address_type).isEqualTo(hci.AddressType.RANDOM_DEVICE_ADDRESS)
-
- self.send_receive_and_check(dut_le_acl, cert_le_acl)
-
- def test_recombination_l2cap_packet(self):
- self.set_privacy_policy_static()
- dut_le_acl, cert_le_acl = self.dut_connects()
- cert_handle = cert_le_acl.handle
- self.enqueue_acl_data(cert_handle, hci.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
- hci.BroadcastFlag.POINT_TO_POINT, bytes(b'\x06\x00\x07\x00Hello'))
- self.enqueue_acl_data(cert_handle, hci.PacketBoundaryFlag.CONTINUING_FRAGMENT, hci.BroadcastFlag.POINT_TO_POINT,
- bytes(b'!'))
-
- assertThat(dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload)
-
- def test_background_connection(self):
- self.set_privacy_policy_static()
-
- # Start background and direct connection
- token_direct = self.dut_le_acl_manager.initiate_connection(
- remote_addr=common.BluetoothAddressWithType(address=common.BluetoothAddress(
- address=bytes('0C:05:04:03:02:02', 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)))
-
- token_background = self.dut_le_acl_manager.initiate_connection(remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)),
- is_direct=False)
-
- # Wait for direct connection timeout
- self.dut_le_acl_manager.wait_for_connection_fail(token_direct)
-
- # Cert Advertises
- advertising_handle = 0
-
- py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
- hci.LegacyAdvertisingEventProperties.ADV_IND, 155, 165)
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- # Check background connection complete
- self.dut_le_acl_manager.complete_outgoing_connection(token_background)
-
- def skip_flaky_test_multiple_background_connections(self):
- self.set_privacy_policy_static()
-
- # Start two background connections
- token_1 = self.dut_le_acl_manager.initiate_connection(remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)),
- is_direct=False)
-
- token_2 = self.dut_le_acl_manager.initiate_connection(remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:02', 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)),
- is_direct=False)
-
- # Cert Advertises
- advertising_handle = 0
-
- py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
- hci.LegacyAdvertisingEventProperties.ADV_IND, 155, 165)
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- # First background connection completes
- connection = self.dut_le_acl_manager.complete_outgoing_connection(token_1)
- connection.close()
-
- # Cert Advertises again
- advertising_handle = 0
-
- py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, '0C:05:04:03:02:02',
- hci.LegacyAdvertisingEventProperties.ADV_IND, 155, 165)
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- # Second background connection completes
- connection = self.dut_le_acl_manager.complete_outgoing_connection(token_2)
- connection.close()
-
- def test_direct_connection(self):
- self.set_privacy_policy_static()
-
- advertising_handle = 0
- py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
- hci.LegacyAdvertisingEventProperties.ADV_IND, 155, 165)
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- # Start direct connection
- token = self.dut_le_acl_manager.initiate_connection(remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)),
- is_direct=True)
- self.dut_le_acl_manager.complete_outgoing_connection(token)
-
- def test_background_connection_list(self):
- self.set_privacy_policy_static()
-
- # Start background connection
- token_background = self.dut_le_acl_manager.initiate_connection(remote_addr=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)),
- is_direct=False)
-
- # Cert Advertises
- advertising_handle = 0
-
- py_hci_adv = self.cert_hci.create_advertisement(advertising_handle, self.cert_random_address,
- hci.LegacyAdvertisingEventProperties.ADV_IND, 155, 165)
-
- py_hci_adv.set_data(b'Im_A_Cert')
- py_hci_adv.set_scan_response(b'Im_A_C')
- py_hci_adv.start()
-
- # Check background connection complete
- self.dut_le_acl_manager.complete_outgoing_connection(token_background)
-
- msg = self.dut_le_acl_manager.is_on_background_list(
- remote_addr=common.BluetoothAddressWithType(address=common.BluetoothAddress(
- address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)))
- assertThat(msg.is_on_background_list).isEqualTo(True)
-
- self.dut_le_acl_manager.remove_from_background_list(
- remote_addr=common.BluetoothAddressWithType(address=common.BluetoothAddress(
- address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)))
-
- msg = self.dut_le_acl_manager.is_on_background_list(
- remote_addr=common.BluetoothAddressWithType(address=common.BluetoothAddress(
- address=bytes(self.cert_random_address, 'utf8')),
- type=int(hci.AddressType.RANDOM_DEVICE_ADDRESS)))
- assertThat(msg.is_on_background_list).isEqualTo(False)
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/le_advertising_manager_test.py b/system/blueberry/tests/gd/hci/le_advertising_manager_test.py
deleted file mode 100644
index a157c981c1..0000000000
--- a/system/blueberry/tests/gd/hci/le_advertising_manager_test.py
+++ /dev/null
@@ -1,328 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-import logging
-
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.matchers import AdvertisingMatchers
-from blueberry.tests.gd.cert.py_hci import PyHci
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.facade import common_pb2 as common
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.facade.hci import controller_facade_pb2 as controller_facade
-from blueberry.facade.hci import \
- le_advertising_manager_facade_pb2 as le_advertising_facade
-from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from blueberry.facade.hci.le_advertising_manager_facade_pb2 import AdvertisingCallbackMsgType
-from blueberry.facade.hci.le_advertising_manager_facade_pb2 import AdvertisingStatus
-
-from mobly import asserts, test_runner
-
-from blueberry.utils import bluetooth
-import hci_packets as hci
-
-
-class LeAdvertisingManagerTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.setup_test(self)
- self.cert_hci = PyHci(self.cert, acl_streaming=True)
- self.dut.callback_event_stream = EventStream(
- self.dut.hci_le_advertising_manager.FetchCallbackEvents(empty_proto.Empty()))
- self.dut.address_event_stream = EventStream(
- self.dut.hci_le_advertising_manager.FetchAddressEvents(empty_proto.Empty()))
-
- def teardown_test(self):
- self.cert_hci.close()
- if self.dut.callback_event_stream is not None:
- safeClose(self.dut.callback_event_stream)
- else:
- logging.info("DUT: Callback Event Stream is None!")
- if self.dut.address_event_stream is not None:
- safeClose(self.dut.address_event_stream)
- else:
- logging.info("DUT: address Event Stream is None!")
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
- def set_address_policy_with_static_address(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'd0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
-
- def create_advertiser(self):
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
- return create_response
-
- def test_le_ad_scan_dut_advertises(self):
- self.set_address_policy_with_static_address()
- self.cert_hci.register_for_le_events(hci.SubeventCode.ADVERTISING_REPORT,
- hci.SubeventCode.EXTENDED_ADVERTISING_REPORT)
-
- # CERT Scans
- self.cert_hci.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0C:05:04:03:02:01')))
-
- self.cert_hci.send_command(
- hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL,
- scanning_phys=1,
- parameters=[
- hci.PhyScanParameters(le_scan_type=hci.LeScanType.ACTIVE,
- le_scan_interval=40,
- le_scan_window=20)
- ]))
-
- self.cert_hci.send_command(
- hci.LeSetExtendedScanEnable(enable=hci.Enable.ENABLED,
- filter_duplicates=hci.FilterDuplicates.DISABLED,
- duration=0,
- period=0))
-
- create_response = self.create_advertiser()
-
- assertThat(self.cert_hci.get_le_event_stream()).emits(lambda packet: b'Im_The_DUT' in packet.payload)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
- self.cert_hci.send_command(
- hci.LeSetScanEnable(le_scan_enable=hci.Enable.DISABLED, filter_duplicates=hci.Enable.DISABLED))
-
- def test_extended_create_advertises(self):
- self.set_address_policy_with_static_address()
- self.cert_hci.register_for_le_events(hci.SubeventCode.ADVERTISING_REPORT,
- hci.SubeventCode.EXTENDED_ADVERTISING_REPORT)
-
- # CERT Scans
- self.cert_hci.send_command(hci.LeSetRandomAddress(random_address=bluetooth.Address('0C:05:04:03:02:01')))
-
- self.cert_hci.send_command(
- hci.LeSetExtendedScanParameters(own_address_type=hci.OwnAddressType.RANDOM_DEVICE_ADDRESS,
- scanning_filter_policy=hci.LeScanningFilterPolicy.ACCEPT_ALL,
- scanning_phys=1,
- parameters=[
- hci.PhyScanParameters(le_scan_type=hci.LeScanType.ACTIVE,
- le_scan_interval=40,
- le_scan_window=20)
- ]))
-
- self.cert_hci.send_command(
- hci.LeSetExtendedScanEnable(enable=hci.Enable.ENABLED,
- filter_duplicates=hci.FilterDuplicates.DISABLED,
- duration=0,
- period=0))
-
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- extended_config = le_advertising_facade.ExtendedAdvertisingConfig(advertising_config=config,
- connectable=True,
- scannable=False,
- directed=False,
- high_duty_directed_connectable=False,
- legacy_pdus=True,
- anonymous=False,
- include_tx_power=True,
- use_le_coded_phy=False,
- secondary_max_skip=0x00,
- secondary_advertising_phy=0x01,
- sid=0x00,
- enable_scan_request_notifications=0x00)
- request = le_advertising_facade.ExtendedCreateAdvertiserRequest(config=extended_config)
- create_response = self.dut.hci_le_advertising_manager.ExtendedCreateAdvertiser(request)
-
- assertThat(self.cert_hci.get_le_event_stream()).emits(lambda packet: b'Im_The_DUT' in packet.payload)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
- self.cert_hci.send_command(
- hci.LeSetScanEnable(le_scan_enable=hci.Enable.DISABLED, filter_duplicates=hci.Enable.DISABLED))
-
- def test_advertising_set_started_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.ADVERTISING_SET_STARTED,
- create_response.advertiser_id, AdvertisingStatus.ADV_SUCCESS,
- 0x00))
-
- def test_enable_advertiser_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- enable_advertiser_request = le_advertising_facade.EnableAdvertiserRequest(
- advertiser_id=create_response.advertiser_id, enable=True)
- self.dut.hci_le_advertising_manager.EnableAdvertiser(enable_advertiser_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.ADVERTISING_ENABLED,
- create_response.advertiser_id, AdvertisingStatus.ADV_SUCCESS,
- 0x01))
-
- def test_disable_advertiser_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- disable_advertiser_request = le_advertising_facade.EnableAdvertiserRequest(
- advertiser_id=create_response.advertiser_id, enable=False)
- self.dut.hci_le_advertising_manager.EnableAdvertiser(disable_advertiser_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.ADVERTISING_ENABLED,
- create_response.advertiser_id, AdvertisingStatus.ADV_SUCCESS,
- 0x00))
-
- def test_set_advertising_data_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT2')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
-
- set_data_request = le_advertising_facade.SetDataRequest(advertiser_id=create_response.advertiser_id,
- set_scan_rsp=False,
- data=[gap_data])
- self.dut.hci_le_advertising_manager.SetData(set_data_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.ADVERTISING_DATA_SET,
- create_response.advertiser_id, AdvertisingStatus.ADV_SUCCESS))
-
- def test_set_scan_response_data_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
-
- set_data_request = le_advertising_facade.SetDataRequest(advertiser_id=create_response.advertiser_id,
- set_scan_rsp=True,
- data=[gap_data])
- self.dut.hci_le_advertising_manager.SetData(set_data_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.SCAN_RESPONSE_DATA_SET,
- create_response.advertiser_id, AdvertisingStatus.ADV_SUCCESS))
-
- def test_set_parameters_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
-
- # The Host shall not issue set parameters command when advertising is enabled
- disable_advertiser_request = le_advertising_facade.EnableAdvertiserRequest(
- advertiser_id=create_response.advertiser_id, enable=False)
- self.dut.hci_le_advertising_manager.EnableAdvertiser(disable_advertiser_request)
-
- config = le_advertising_facade.AdvertisingConfig(
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
-
- set_parameters_request = le_advertising_facade.SetParametersRequest(advertiser_id=create_response.advertiser_id,
- config=config)
- self.dut.hci_le_advertising_manager.SetParameters(set_parameters_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.ADVERTISING_PARAMETERS_UPDATED,
- create_response.advertiser_id, AdvertisingStatus.ADV_SUCCESS))
-
- def test_set_periodic_parameters_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
-
- config = le_advertising_facade.PeriodicAdvertisingParameters(
- min_interval=512,
- max_interval=768,
- advertising_property=le_advertising_facade.AdvertisingProperty.INCLUDE_TX_POWER)
-
- set_periodic_parameters_request = le_advertising_facade.SetPeriodicParametersRequest(
- advertiser_id=create_response.advertiser_id, config=config)
- self.dut.hci_le_advertising_manager.SetPeriodicParameters(set_periodic_parameters_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(
- AdvertisingCallbackMsgType.PERIODIC_ADVERTISING_PARAMETERS_UPDATED, create_response.advertiser_id))
-
- def test_set_periodic_data_callback(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT2')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
-
- set_periodic_data_request = le_advertising_facade.SetPeriodicDataRequest(
- advertiser_id=create_response.advertiser_id, data=[gap_data])
- self.dut.hci_le_advertising_manager.SetPeriodicData(set_periodic_data_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.PERIODIC_ADVERTISING_DATA_SET,
- create_response.advertiser_id))
-
- def test_enable_periodic_advertising_callback(self):
- check_feature = self.dut.hci_controller.SupportsBlePeriodicAdvertising(empty_proto.Empty())
- if not check_feature.supported:
- asserts.skip("Periodic advertising not supported.")
-
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- enable_periodic_advertising_request = le_advertising_facade.EnablePeriodicAdvertisingRequest(
- advertiser_id=create_response.advertiser_id, enable=True, include_adi=False)
- self.dut.hci_le_advertising_manager.EnablePeriodicAdvertising(enable_periodic_advertising_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- AdvertisingMatchers.AdvertisingCallbackMsg(AdvertisingCallbackMsgType.PERIODIC_ADVERTISING_ENABLED,
- create_response.advertiser_id))
-
- def test_get_own_address(self):
- self.set_address_policy_with_static_address()
- create_response = self.create_advertiser()
- get_own_address_request = le_advertising_facade.GetOwnAddressRequest(
- advertiser_id=create_response.advertiser_id)
- self.dut.hci_le_advertising_manager.GetOwnAddress(get_own_address_request)
- address_with_type = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'd0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
- assertThat(self.dut.address_event_stream).emits(
- AdvertisingMatchers.AddressMsg(AdvertisingCallbackMsgType.OWN_ADDRESS_READ, create_response.advertiser_id,
- address_with_type))
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/le_extended_config.json b/system/blueberry/tests/gd/hci/le_extended_config.json
deleted file mode 100644
index ae81c0af73..0000000000
--- a/system/blueberry/tests/gd/hci/le_extended_config.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "supported_commands" : ["b3", "ff", "ef", "01", "ce", "fd", "81", "ff", "3f", "0f",
- "40", "1e", "f0", "03", "e8", "02", "03", "d6", "81", "9f",
- "1c", "00", "00", "00", "40", "f7", "ff", "a7", "0f", "20",
- "00", "00", "4a", "80", "78", "ff", "ff", "ff", "00", "00",],
-}
diff --git a/system/blueberry/tests/gd/hci/le_extended_scanning_manager_test.py b/system/blueberry/tests/gd/hci/le_extended_scanning_manager_test.py
deleted file mode 100644
index 890adde06d..0000000000
--- a/system/blueberry/tests/gd/hci/le_extended_scanning_manager_test.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.tests.gd.hci.le_scanning_manager_test_blueberry import LeScanningManagerTestBase
-from mobly import test_runner
-
-
-class LeExtendedScanningManagerTest(gd_base_test.GdBaseTestClass, LeScanningManagerTestBase):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.set_controller_properties_path(self,
- 'blueberry/tests/gd/hci/le_extended_config.json')
- gd_base_test.GdBaseTestClass.setup_test(self)
- LeScanningManagerTestBase.setup_test(self, self.cert, self.dut)
-
- def teardown_test(self):
- LeScanningManagerTestBase.teardown_test(self)
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/le_legacy_config.json b/system/blueberry/tests/gd/hci/le_legacy_config.json
deleted file mode 100644
index 34e9c95a9f..0000000000
--- a/system/blueberry/tests/gd/hci/le_legacy_config.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "supported_commands" : ["b3", "ff", "ef", "01", "ce", "fd", "81", "ff", "3f", "0f",
- "40", "1e", "f0", "03", "e8", "02", "03", "d6", "81", "9f",
- "1c", "00", "00", "00", "40", "f7", "ff", "a7", "0f", "20",
- "00", "00", "4a", "80", "78", "0e", "00", "00", "00", "00",],
-}
diff --git a/system/blueberry/tests/gd/hci/le_scanning_manager_test.py b/system/blueberry/tests/gd/hci/le_scanning_manager_test.py
deleted file mode 100644
index 0a4faea078..0000000000
--- a/system/blueberry/tests/gd/hci/le_scanning_manager_test.py
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-import logging
-
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.matchers import ScanningMatchers
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.facade import common_pb2 as common
-from blueberry.facade import rootservice_pb2 as facade_rootservice
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.facade.hci import hci_facade_pb2 as hci_facade
-from blueberry.facade.hci import le_scanning_manager_facade_pb2 as le_scanning_facade
-from blueberry.facade.hci import le_advertising_manager_facade_pb2 as le_advertising_facade
-from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from blueberry.facade.hci.le_scanning_manager_facade_pb2 import ScanningCallbackMsgType
-from blueberry.facade.hci.le_scanning_manager_facade_pb2 import ScanningStatus
-from mobly import test_runner
-import hci_packets as hci
-
-
-class LeScanningManagerTestBase():
-
- def setup_test(self, cert, dut):
- self.cert = cert
- self.dut = dut
- self.dut.callback_event_stream = EventStream(
- self.dut.hci_le_scanning_manager.FetchCallbackEvents(empty_proto.Empty()))
- self.dut.advertising_report_stream = EventStream(
- self.dut.hci_le_scanning_manager.FetchAdvertisingReports(empty_proto.Empty()))
-
- def teardown_test(self):
- if self.dut.callback_event_stream is not None:
- safeClose(self.dut.callback_event_stream)
- else:
- logging.info("DUT: Callback Event Stream is None!")
- if self.dut.advertising_report_stream is not None:
- safeClose(self.dut.advertising_report_stream)
- else:
- logging.info("DUT: Advertising Report Stream is None!")
-
- def register_for_event(self, event_code):
- msg = hci_facade.EventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterEventHandler(msg)
-
- def register_for_le_event(self, event_code):
- msg = hci_facade.LeSubeventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterLeEventHandler(msg)
-
- def enqueue_hci_command(self, command, expect_complete):
- cmd_bytes = bytes(command.serialize())
- cmd = common.Data(payload=cmd_bytes)
- if (expect_complete):
- self.cert.hci.EnqueueCommandWithComplete(cmd)
- else:
- self.cert.hci.EnqueueCommandWithStatus(cmd)
-
- def set_address_policy_with_static_address(self):
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
- cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(cert_privacy_policy)
-
- def test_le_ad_scan_dut_scans(self):
- self.set_address_policy_with_static_address()
- # CERT Advertises
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_CERT!')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- gap_scan_name = hci.GapData(data_type=hci.GapDataType.SHORTENED_LOCAL_NAME, data=list(bytes(b'CERT!')))
- gap_scan_data = le_advertising_facade.GapDataMsg(data=gap_scan_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- scan_response=[gap_scan_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- scan_request = le_scanning_facade.ScanRequest(start=True)
- self.dut.hci_le_scanning_manager.Scan(scan_request)
-
- self.dut.advertising_report_stream.assert_event_occurs(lambda packet: b'Im_The_CERT' in packet.event)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
-
- def test_register_scanner_callback(self):
- self.set_address_policy_with_static_address()
- register_request = le_scanning_facade.RegisterScannerRequest(uuid=123)
- self.dut.hci_le_scanning_manager.RegisterScanner(register_request)
- assertThat(self.dut.callback_event_stream).emits(
- ScanningMatchers.ScanningCallbackMsg(ScanningCallbackMsgType.SCANNER_REGISTERED,
- ScanningStatus.SCAN_SUCCESS, 123))
-
- def test_register_scanner_with_same_uuid(self):
- self.set_address_policy_with_static_address()
- register_request = le_scanning_facade.RegisterScannerRequest(uuid=123)
- self.dut.hci_le_scanning_manager.RegisterScanner(register_request)
- assertThat(self.dut.callback_event_stream).emits(
- ScanningMatchers.ScanningCallbackMsg(ScanningCallbackMsgType.SCANNER_REGISTERED,
- ScanningStatus.SCAN_SUCCESS, 123))
- self.dut.hci_le_scanning_manager.RegisterScanner(register_request)
- assertThat(self.dut.callback_event_stream).emits(
- ScanningMatchers.ScanningCallbackMsg(ScanningCallbackMsgType.SCANNER_REGISTERED,
- ScanningStatus.SCAN_INTERNAL_ERROR, 123))
-
- def test_set_scan_parameters_callback(self):
- self.set_address_policy_with_static_address()
- set_scan_parameters_request = le_scanning_facade.SetScanParametersRequest(
- scanner_id=0x01,
- scan_type=le_scanning_facade.LeScanType.ACTIVE,
- scan_interval=0x10,
- scan_window=0x04,
- scan_phy=0x01)
- self.dut.hci_le_scanning_manager.SetScanParameters(set_scan_parameters_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- ScanningMatchers.ScanningCallbackMsg(ScanningCallbackMsgType.SET_SCANNER_PARAMETER_COMPLETE,
- ScanningStatus.SCAN_SUCCESS, 0x01))
-
- def test_set_scan_parameters_with_invalid_parameter(self):
- self.set_address_policy_with_static_address()
- set_scan_parameters_request = le_scanning_facade.SetScanParametersRequest(
- scanner_id=0x01,
- scan_type=le_scanning_facade.LeScanType.ACTIVE,
- scan_interval=0x00,
- scan_window=0x00,
- scan_phy=0x01)
- self.dut.hci_le_scanning_manager.SetScanParameters(set_scan_parameters_request)
-
- assertThat(self.dut.callback_event_stream).emits(
- ScanningMatchers.ScanningCallbackMsg(ScanningCallbackMsgType.SET_SCANNER_PARAMETER_COMPLETE,
- ScanningStatus.SCAN_ILLEGAL_PARAMETER))
-
- def test_active_scan(self):
- self.set_address_policy_with_static_address()
- # CERT Advertises
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Scan response data')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- scan_response=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- set_scan_parameters_request = le_scanning_facade.SetScanParametersRequest(
- scanner_id=0x01,
- scan_type=le_scanning_facade.LeScanType.ACTIVE,
- scan_interval=0x10,
- scan_window=0x04,
- scan_phy=0x01)
- self.dut.hci_le_scanning_manager.SetScanParameters(set_scan_parameters_request)
- scan_request = le_scanning_facade.ScanRequest(start=True)
- self.dut.hci_le_scanning_manager.Scan(scan_request)
-
- self.dut.advertising_report_stream.assert_event_occurs(lambda packet: b'Scan response data' in packet.event)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
-
- def test_passive_scan(self):
- self.set_address_policy_with_static_address()
- # CERT Advertises
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Scan response data')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- scan_response=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- set_scan_parameters_request = le_scanning_facade.SetScanParametersRequest(
- scanner_id=0x01,
- scan_type=le_scanning_facade.LeScanType.PASSIVE,
- scan_interval=0x10,
- scan_window=0x04,
- scan_phy=0x01)
- self.dut.hci_le_scanning_manager.SetScanParameters(set_scan_parameters_request)
- scan_request = le_scanning_facade.ScanRequest(start=True)
- self.dut.hci_le_scanning_manager.Scan(scan_request)
-
- self.dut.advertising_report_stream.assert_event_occurs_at_most(
- lambda packet: b'Scan response data' in packet.event, 0)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
-
-
-class LeScanningManagerTest(gd_base_test.GdBaseTestClass, LeScanningManagerTestBase):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.set_controller_properties_path(self,
- 'blueberry/tests/gd/hci/le_legacy_config.json')
- gd_base_test.GdBaseTestClass.setup_test(self)
- LeScanningManagerTestBase.setup_test(self, self.cert, self.dut)
-
- def teardown_test(self):
- LeScanningManagerTestBase.teardown_test(self)
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/hci/le_scanning_with_security_test.py b/system/blueberry/tests/gd/hci/le_scanning_with_security_test.py
deleted file mode 100644
index 79f4e3a762..0000000000
--- a/system/blueberry/tests/gd/hci/le_scanning_with_security_test.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - 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.
-
-from blueberry.tests.gd.cert.event_stream import EventStream
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert import gd_base_test
-from google.protobuf import empty_pb2 as empty_proto
-from blueberry.facade.hci import hci_facade_pb2 as hci_facade
-from blueberry.facade.hci import le_advertising_manager_facade_pb2 as le_advertising_facade
-from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from blueberry.facade.hci import le_scanning_manager_facade_pb2 as le_scanning_facade
-from blueberry.facade import common_pb2 as common
-from mobly import test_runner
-import hci_packets as hci
-
-
-class LeScanningWithSecurityTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='SECURITY', cert_module='HCI_INTERFACES')
-
- def register_for_event(self, event_code):
- msg = hci_facade.EventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterEventHandler(msg)
-
- def register_for_le_event(self, event_code):
- msg = hci_facade.LeSubeventCodeMsg(code=int(event_code))
- self.cert.hci.RegisterLeEventHandler(msg)
-
- def enqueue_hci_command(self, command, expect_complete):
- cmd_bytes = bytes(command.serialize())
- cmd = common.Data(command=cmd_bytes)
- if (expect_complete):
- self.cert.hci.EnqueueCommandWithComplete(cmd)
- else:
- self.cert.hci.EnqueueCommandWithStatus(cmd)
-
- def test_le_ad_scan_dut_scans(self):
- """
- Verify that the IUT address policy is correctly initiated by SecurityManager, and we can start a scan.
- """
- cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:05:04:03:02:01')),
- type=common.RANDOM_DEVICE_ADDRESS),
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(cert_privacy_policy)
- with EventStream(
- # DUT Scans
- self.dut.hci_le_scanning_manager.FetchAdvertisingReports(empty_proto.Empty()
- )) as advertising_event_stream:
-
- # CERT Advertises
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_CERT!')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- gap_scan_name = hci.GapData(data_type=hci.GapDataType.SHORTENED_LOCAL_NAME, data=list(bytes(b'CERT!')))
- gap_scan_data = le_advertising_facade.GapDataMsg(data=gap_scan_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- scan_response=[gap_scan_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
- create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)
-
- scan_request = le_scanning_facade.ScanRequest(start=True)
- self.dut.hci_le_scanning_manager.Scan(scan_request)
-
- assertThat(advertising_event_stream).emits(lambda packet: b'Im_The_CERT' in packet.event)
-
- remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
- self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/host_config.yaml b/system/blueberry/tests/gd/host_config.yaml
deleted file mode 100644
index 15155db8d7..0000000000
--- a/system/blueberry/tests/gd/host_config.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-_description: Bluetooth cert testing
-TestBeds:
- - Name: HostOnlyCert
- Controllers:
- rootcanal:
- test_port: '6401'
- hci_port: '6402'
- link_layer_port: '6403'
- GdDevice:
- - grpc_port: '8998'
- grpc_root_server_port: '8996'
- signal_port: '8994'
- label: cert
- name: Cert Device
- cmd:
- - "$GD_ROOT/bluetooth_stack_with_facade"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--rootcanal-port=$(rootcanal_port)"
- - "--signal-port=$(signal_port)"
- - grpc_port: '8999'
- grpc_root_server_port: '8997'
- signal_port: '8995'
- label: dut
- name: DUT Device
- cmd:
- - "$GD_ROOT/bluetooth_stack_with_facade"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--rootcanal-port=$(rootcanal_port)"
- - "--signal-port=$(signal_port)"
-logpath: "/tmp/logs"
diff --git a/system/blueberry/tests/gd/iso/cert_le_iso.py b/system/blueberry/tests/gd/iso/cert_le_iso.py
deleted file mode 100644
index ee478e61e4..0000000000
--- a/system/blueberry/tests/gd/iso/cert_le_iso.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-import logging
-
-from blueberry.tests.gd.cert.closable import Closable
-from blueberry.tests.gd.cert.py_le_iso import PyLeIso
-
-
-class CertLeIso(Closable):
-
- def __init__(self, device):
- self._device = device
- self._le_iso = PyLeIso(device)
-
- def close(self):
- logging.info("DUT: close")
- self._le_iso.close()
-
- def le_set_cig_parameters(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, peripherals_clock_accuracy,
- packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_id,
- max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m, rtn_m_to_s, rtn_s_to_m):
- return self._le_iso.le_set_cig_parameters(
- cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_id, max_sdu_m_to_s, max_sdu_s_to_m,
- phy_m_to_s, phy_s_to_m, rtn_m_to_s, rtn_s_to_m)
-
- def le_set_cig_parameters_test(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s, ft_s_to_m,
- iso_interval, peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_configs):
- return self._le_iso.le_set_cig_parameters_test(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, ft_m_to_s,
- ft_s_to_m, iso_interval, peripherals_clock_accuracy, packing,
- framing, max_transport_latency_m_to_s,
- max_transport_latency_s_to_m, cis_configs)
-
- def wait_le_set_cig_parameters_complete(self):
- return self._le_iso.wait_le_set_cig_parameters_complete()
-
- def le_cretate_cis(self, cis_and_acl_handle_array):
- self._le_iso.le_create_cis(cis_and_acl_handle_array)
-
- def wait_le_cis_established(self):
- return self._le_iso.wait_le_cis_established()
diff --git a/system/blueberry/tests/gd/iso/le_iso_test.py b/system/blueberry/tests/gd/iso/le_iso_test.py
deleted file mode 100644
index e5af99b314..0000000000
--- a/system/blueberry/tests/gd/iso/le_iso_test.py
+++ /dev/null
@@ -1,252 +0,0 @@
-#
-# Copyright 2021 - 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.
-
-from blueberry.tests.gd.cert.closable import safeClose
-from blueberry.tests.gd.cert.matchers import IsoMatchers
-from blueberry.tests.gd.cert.metadata import metadata
-from blueberry.tests.gd.cert.py_le_acl_manager import PyLeAclManager
-from blueberry.tests.gd.cert.py_le_iso import PyLeIso
-from blueberry.tests.gd.cert.py_le_iso import CisTestParameters
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.gd.cert import gd_base_test
-from blueberry.tests.gd.iso.cert_le_iso import CertLeIso
-from blueberry.facade import common_pb2 as common
-from blueberry.facade.hci import controller_facade_pb2 as controller_facade
-from blueberry.facade.hci import le_advertising_manager_facade_pb2 as le_advertising_facade
-from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from mobly import asserts
-from mobly import test_runner
-import hci_packets as hci
-
-
-class LeIsoTest(gd_base_test.GdBaseTestClass):
-
- def setup_class(self):
- gd_base_test.GdBaseTestClass.setup_class(self, dut_module='HCI_INTERFACES', cert_module='HCI_INTERFACES')
-
- def setup_test(self):
- gd_base_test.GdBaseTestClass.setup_test(self)
-
- self.dut_le_acl_manager = PyLeAclManager(self.dut)
- self.cert_le_acl_manager = PyLeAclManager(self.cert)
-
- self.dut_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
- self.cert_address = common.BluetoothAddressWithType(
- address=common.BluetoothAddress(address=bytes(b'C0:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
- dut_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.dut_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(dut_privacy_policy)
- privacy_policy = le_initiator_address_facade.PrivacyPolicy(
- address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
- address_with_type=self.cert_address,
- rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
- minimum_rotation_time=0,
- maximum_rotation_time=0)
- self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
-
- self.dut_iso = PyLeIso(self.dut)
- self.cert_iso = CertLeIso(self.cert)
-
- def teardown_test(self):
- self.dut_iso.close()
- self.cert_iso.close()
-
- safeClose(self.dut_le_acl_manager)
- safeClose(self.cert_le_acl_manager)
- gd_base_test.GdBaseTestClass.teardown_test(self)
-
- #cert becomes central of connection, dut peripheral
- def _setup_link_from_cert(self):
- # DUT Advertises
- gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT')))
- gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize())
- config = le_advertising_facade.AdvertisingConfig(
- advertisement=[gap_data],
- interval_min=512,
- interval_max=768,
- advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
- own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS,
- channel_map=7,
- filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
- request = le_advertising_facade.CreateAdvertiserRequest(config=config)
- create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
- self.dut_le_acl = self.dut_le_acl_manager.listen_for_incoming_connections()
- self.cert_le_acl = self.cert_le_acl_manager.connect_to_remote(self.dut_address)
-
- def _setup_cis_from_cert(self, cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m, peripherals_clock_accuracy,
- packing, framing, max_transport_latency_m_to_s, max_transport_latency_s_to_m, cis_id,
- max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m, bn_m_to_s, bn_s_to_m):
-
- self.cert_iso.le_set_cig_parameters(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m,
- peripherals_clock_accuracy, packing, framing, max_transport_latency_m_to_s,
- max_transport_latency_s_to_m, cis_id, max_sdu_m_to_s, max_sdu_s_to_m,
- phy_m_to_s, phy_s_to_m, bn_m_to_s, bn_s_to_m)
-
- cis_handles = self.cert_iso.wait_le_set_cig_parameters_complete()
-
- cis_handle = cis_handles[0]
-
- acl_connection_handle = self.cert_le_acl.handle
- self.cert_iso.le_cretate_cis([(cis_handle, acl_connection_handle)])
- dut_cis_stream = self.dut_iso.wait_le_cis_established()
- cert_cis_stream = self.cert_iso.wait_le_cis_established()
- return (dut_cis_stream, cert_cis_stream)
-
- def skip_if_iso_not_supported(self):
- supported = self.dut.hci_controller.IsSupportedCommand(
- controller_facade.OpCodeMsg(op_code=int(hci.OpCode.LE_SET_CIG_PARAMETERS)))
- if (not supported.supported):
- asserts.skip("Skipping this test. The chip doesn't support LE ISO")
-
- @metadata(pts_test_id="IAL/CIS/UNF/SLA/BV-01-C",
- pts_test_name="connected isochronous stream, unframed data, peripheral role")
- def test_iso_cis_unf_sla_bv_01_c(self):
- self.skip_if_iso_not_supported()
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0
- sdu_interval_s_to_m = 0x186a
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 0
- max_transport_latency_m_to_s = 0
- max_transport_latency_s_to_m = 7
- cis_id = 0x01
- max_sdu_m_to_s = 0
- max_sdu_s_to_m = 100
- phy_m_to_s = 0x02
- phy_s_to_m = 0x02
- bn_m_to_s = 0
- bn_s_to_m = 2
-
- self._setup_link_from_cert()
- (dut_cis_stream,
- cert_cis_stream) = self._setup_cis_from_cert(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m,
- peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_id, max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m,
- bn_m_to_s, bn_s_to_m)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
- @metadata(pts_test_id="IAL/CIS/UNF/SLA/BV-25-C",
- pts_test_name="connected isochronous stream, unframed data, peripheral role")
- def test_iso_cis_unf_sla_bv_25_c(self):
- self.skip_if_iso_not_supported()
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0x7530
- sdu_interval_s_to_m = 0x7530
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 0
- max_transport_latency_m_to_s = 30
- max_transport_latency_s_to_m = 30
- cis_id = 0x01
- max_sdu_m_to_s = 100
- max_sdu_s_to_m = 100
- phy_m_to_s = 0x02
- phy_s_to_m = 0x02
- bn_m_to_s = 3
- bn_s_to_m = 1
-
- self._setup_link_from_cert()
- (dut_cis_stream,
- cert_cis_stream) = self._setup_cis_from_cert(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m,
- peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_id, max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m,
- bn_m_to_s, bn_s_to_m)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
- @metadata(pts_test_id="IAL/CIS/FRA/SLA/BV-03-C",
- pts_test_name="connected isochronous stream, framed data, peripheral role")
- def test_iso_cis_fra_sla_bv_03_c(self):
- self.skip_if_iso_not_supported()
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0x0000
- sdu_interval_s_to_m = 0x4e30
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 1
- max_transport_latency_m_to_s = 0
- max_transport_latency_s_to_m = 21
- cis_id = 0x01
- max_sdu_m_to_s = 0
- max_sdu_s_to_m = 100
- phy_m_to_s = 0x02
- phy_s_to_m = 0x02
- bn_m_to_s = 0
- bn_s_to_m = 2
-
- self._setup_link_from_cert()
- (dut_cis_stream,
- cert_cis_stream) = self._setup_cis_from_cert(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m,
- peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_id, max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m,
- bn_m_to_s, bn_s_to_m)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
- @metadata(pts_test_id="IAL/CIS/FRA/SLA/BV-26-C",
- pts_test_name="connected isochronous stream, framed data, peripheral role")
- def test_iso_cis_fra_sla_bv_26_c(self):
- self.skip_if_iso_not_supported()
- """
- Verify that the IUT can send an SDU with length ≤ the Isochronous PDU length.
- """
- cig_id = 0x01
- sdu_interval_m_to_s = 0x14D5
- sdu_interval_s_to_m = 0x14D5
- peripherals_clock_accuracy = 0
- packing = 0
- framing = 1
- max_transport_latency_m_to_s = 6
- max_transport_latency_s_to_m = 6
- cis_id = 0x01
- max_sdu_m_to_s = 100
- max_sdu_s_to_m = 100
- phy_m_to_s = 0x02
- phy_s_to_m = 0x02
- bn_m_to_s = 1
- bn_s_to_m = 1
-
- self._setup_link_from_cert()
- (dut_cis_stream,
- cert_cis_stream) = self._setup_cis_from_cert(cig_id, sdu_interval_m_to_s, sdu_interval_s_to_m,
- peripherals_clock_accuracy, packing, framing,
- max_transport_latency_m_to_s, max_transport_latency_s_to_m,
- cis_id, max_sdu_m_to_s, max_sdu_s_to_m, phy_m_to_s, phy_s_to_m,
- bn_m_to_s, bn_s_to_m)
- dut_cis_stream.send(b'abcdefgh' * 10)
- assertThat(cert_cis_stream).emits(IsoMatchers.Data(b'abcdefgh' * 10))
-
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/system/blueberry/tests/gd/rust_devices_config.yaml b/system/blueberry/tests/gd/rust_devices_config.yaml
deleted file mode 100644
index 9414c52b59..0000000000
--- a/system/blueberry/tests/gd/rust_devices_config.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-_description: Bluetooth cert testing
-TestBeds:
- - Name: AndroidDeviceCert
- Controllers:
- GdDevice:
- - grpc_port: '8898'
- grpc_root_server_port: '8896'
- signal_port: '8894'
- label: cert
- serial_number: 'CERT'
- name: Cert Device
- cmd:
- - "adb"
- - "-s"
- - "$(serial_number)"
- - "shell"
- - "ASAN_OPTIONS=detect_container_overflow=0"
- - "/system/bin/bluetooth_with_facades"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--btsnoop=/data/misc/bluetooth/logs/btsnoop_hci.log"
- - "--btsnooz=/data/misc/bluetooth/logs/btsnooz_hci.log"
- - "--btconfig=/data/misc/bluedroid/bt_config.conf"
- - "--signal-port=$(signal_port)"
- - grpc_port: '8899'
- grpc_root_server_port: '8897'
- signal_port: '8895'
- label: dut
- serial_number: 'DUT'
- name: DUT Device
- cmd:
- - "adb"
- - "-s"
- - "$(serial_number)"
- - "shell"
- - "ASAN_OPTIONS=detect_container_overflow=0"
- - "/system/bin/bluetooth_with_facades"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--btsnoop=/data/misc/bluetooth/logs/btsnoop_hci.log"
- - "--btsnooz=/data/misc/bluetooth/logs/btsnooz_hci.log"
- - "--btconfig=/data/misc/bluedroid/bt_config.conf"
- - "--signal-port=$(signal_port)"
-logpath: "/tmp/logs" \ No newline at end of file
diff --git a/system/blueberry/tests/gd/rust_host_config.yaml b/system/blueberry/tests/gd/rust_host_config.yaml
deleted file mode 100644
index 527a1d11ce..0000000000
--- a/system/blueberry/tests/gd/rust_host_config.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-_description: Bluetooth cert testing
-TestBeds:
- - Name: HostOnlyCert
- Controllers:
- rootcanal:
- test_port: '6401'
- hci_port: '6402'
- link_layer_port: '6403'
- GdDevice:
- - grpc_port: '8998'
- grpc_root_server_port: '8996'
- signal_port: '8994'
- label: cert
- name: Cert Device
- cmd:
- - "$GD_ROOT/bluetooth_with_facades"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--rootcanal-port=$(rootcanal_port)"
- - "--signal-port=$(signal_port)"
- - grpc_port: '8999'
- grpc_root_server_port: '8997'
- signal_port: '8995'
- label: dut
- name: DUT Device
- cmd:
- - "$GD_ROOT/bluetooth_with_facades"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--rootcanal-port=$(rootcanal_port)"
- - "--signal-port=$(signal_port)"
-logpath: "/tmp/logs"
diff --git a/system/blueberry/tests/topshim/adapter/adapter_test.py b/system/blueberry/tests/topshim/adapter/adapter_test.py
deleted file mode 100644
index c2f1f1ee24..0000000000
--- a/system/blueberry/tests/topshim/adapter/adapter_test.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.topshim.lib.topshim_base_test import TopshimBaseTest
-from blueberry.tests.topshim.lib.adapter_client import AdapterClient
-
-from mobly import test_runner
-
-
-class AdapterTest(TopshimBaseTest):
-
- def test_verify_adapter_started(self):
- print("Adapter is verified when test starts")
-
- def test_enable_inquiry_scan(self):
- status, discovery_mode = self.dut().enable_inquiry_scan()
- assertThat(status).isEqualTo("Success")
- assertThat(discovery_mode).isEqualTo("ConnectableDiscoverable")
-
- def test_enable_page_scan(self):
- status, discovery_mode = self.dut().enable_page_scan()
- assertThat(status).isEqualTo("Success")
- assertThat(discovery_mode).isEqualTo("Connectable")
-
- def test_disable_page_scan(self):
- status, discovery_mode = self.dut().disable_page_scan()
- assertThat(status).isEqualTo("Success")
- assertThat(discovery_mode).isEqualTo("None_")
-
- def test_set_local_io_caps(self):
- status, caps = self.dut().set_local_io_caps(3)
- assertThat(status).isEqualTo("Success")
- assertThat(caps).isEqualTo("None_")
-
- def test_start_discovery(self):
- state = self.dut().toggle_discovery(True)
- assertThat(state).isEqualTo("Started")
- # Reset device to not discovering.
- self.dut().toggle_discovery(False)
-
- def test_cancel_discovery(self):
- self.dut().toggle_discovery(True)
- state = self.dut().toggle_discovery(False)
- assertThat(state).isEqualTo("Stopped")
-
- def test_find_device_device_available(self):
- self.dut().enable_inquiry_scan()
- self.cert().enable_inquiry_scan()
- self.dut().toggle_discovery(True)
- device_addr = self.dut().find_device()
- assertThat(device_addr).isNotNone()
- # Reset DUT device discovering and scanning to None
- self.dut().disable_page_scan()
- self.dut().toggle_discovery(False)
- # Reset CERT device to not discoverable
- self.cert().disable_page_scan()
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/system/blueberry/tests/topshim/hfp/hfp_test.py b/system/blueberry/tests/topshim/hfp/hfp_test.py
deleted file mode 100644
index c8e8b95fdd..0000000000
--- a/system/blueberry/tests/topshim/hfp/hfp_test.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.topshim.lib.topshim_base_test import TopshimBaseTest
-from blueberry.tests.topshim.lib.topshim_device import TRANSPORT_CLASSIC
-
-from mobly import test_runner
-
-
-class HfpTest(TopshimBaseTest):
-
- def setup_test(self):
- super().setup_test()
- # Pair dut and cert device.
- self.dut().enable_inquiry_scan()
- self.cert().enable_inquiry_scan()
- self.dut().toggle_discovery(True)
- self.__paired_device = self.dut().find_device()
- self.dut().create_bond(address=self.__paired_device, transport=TRANSPORT_CLASSIC)
-
- def teardown_test(self):
- super().teardown_test()
- # Test teardown for dut and cert reset.
- self.dut().toggle_discovery(False)
- self.dut().disable_page_scan()
- self.cert().disable_page_scan()
-
- def test_hfp_connect_with_bond(self):
- state, _ = self.dut().start_slc(address=self.__paired_device)
- assertThat(state).isEqualTo("Connecting")
- state, _ = self.dut().wait_for_hfp_connection_state_change()
- assertThat(state).isEqualTo("Connected")
- state, conn_addr = self.dut().wait_for_hfp_connection_state_change()
- assertThat(state).isEqualTo("SlcConnected")
- assertThat(conn_addr).isEqualTo(self.__paired_device)
-
- #Extra steps to remove bonding to complete teardown.
- self.dut().remove_bonded_device(self.__paired_device)
- # This is required currently so that the HFP connection state change
- # callback doesn't affect other tests.
- self.dut().wait_for_hfp_connection_state_change()
-
- def test_hfp_disconnect_with_bond(self):
- state, _ = self.dut().start_slc(address=self.__paired_device)
- self.dut().wait_for_hfp_connection_state_change() # To connected
- self.dut().wait_for_hfp_connection_state_change() # To SLC connected
-
- # Actual test for stopping SLC connection.
- state, _ = self.dut().stop_slc(address=self.__paired_device)
- assertThat(state).isEqualTo("Disconnecting")
- state, _ = self.dut().wait_for_hfp_connection_state_change()
- assertThat(state).isEqualTo("Disconnected")
- #Extra steps to remove bonding to complete teardown.
- self.dut().remove_bonded_device(self.__paired_device)
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/system/blueberry/tests/topshim/lib/adapter_client.py b/system/blueberry/tests/topshim/lib/adapter_client.py
deleted file mode 100644
index e85d379569..0000000000
--- a/system/blueberry/tests/topshim/lib/adapter_client.py
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-import asyncio
-import grpc
-
-from blueberry.facade.topshim import facade_pb2
-from blueberry.facade.topshim import facade_pb2_grpc
-from blueberry.tests.topshim.lib.async_closable import AsyncClosable
-
-from google.protobuf import empty_pb2 as empty_proto
-
-
-class AdapterClient(AsyncClosable):
- """
- Wrapper gRPC interface to the Topshim/BTIF layer
- """
- # Timeout for async wait
- DEFAULT_TIMEOUT = 2
- __task_list = []
- __channel = None
- __adapter_stub = None
- __adapter_event_stream = None
-
- def __init__(self, port=8999):
- self.__channel = grpc.aio.insecure_channel("localhost:%d" % port)
- self.__adapter_stub = facade_pb2_grpc.AdapterServiceStub(self.__channel)
- self.__adapter_event_stream = self.__adapter_stub.FetchEvents(facade_pb2.FetchEventsRequest())
-
- async def close(self):
- for task in self.__task_list:
- if task.done() or task.cancelled():
- continue
- task.cancel()
- self.__task_list.clear()
- await self.__channel.close()
-
- async def __get_next_event(self, event, future):
- """Get the future of next event from the stream"""
- while True:
- e = await self.__adapter_event_stream.read()
-
- # Match event by some condition.
- if e.event_type == event:
- future.set_result(e.params)
- break
- else:
- print("Got '%s'; expecting '%s'" % (e.event_type, event))
- print(e)
-
- async def _listen_for_event(self, event):
- """Start fetching events"""
- future = asyncio.get_running_loop().create_future()
- task = asyncio.get_running_loop().create_task(self.__get_next_event(event, future))
- self.__task_list.append(task)
- try:
- await asyncio.wait_for(future, AdapterClient.DEFAULT_TIMEOUT)
- except:
- task.cancel()
- print("Failed to get event", event)
- return future
-
- async def _verify_adapter_started(self):
- future = await self._listen_for_event(facade_pb2.EventType.ADAPTER_STATE)
- params = future.result()
- return params["state"].data[0] == "ON"
-
- async def toggle_stack(self, is_start=True):
- """Enable/disable the stack"""
- await self.__adapter_stub.ToggleStack(facade_pb2.ToggleStackRequest(start_stack=is_start))
- return await self._verify_adapter_started()
-
- async def enable_inquiry_scan(self):
- """Enable inquiry scan (Required to make device connectable and discoverable by other devices)"""
- await self.__adapter_stub.SetDiscoveryMode(facade_pb2.SetDiscoveryModeRequest(enable_inquiry_scan=True))
- return await self._listen_for_event(facade_pb2.EventType.ADAPTER_PROPERTY)
-
- async def enable_page_scan(self):
- """Enable page scan (might be used for A2dp sink to be discoverable)"""
- await self.__adapter_stub.SetDiscoveryMode(facade_pb2.SetDiscoveryModeRequest(enable_page_scan=True))
- return await self._listen_for_event(facade_pb2.EventType.ADAPTER_PROPERTY)
-
- async def disable_page_scan(self):
- """Enable page scan (might be used for A2dp sink to be discoverable)"""
- await self.__adapter_stub.SetDiscoveryMode(facade_pb2.SetDiscoveryModeRequest(enable_page_scan=False))
- return await self._listen_for_event(facade_pb2.EventType.ADAPTER_PROPERTY)
-
- async def clear_event_filter(self):
- await self.__adapter_stub.ClearEventFilter(empty_proto.Empty())
-
- async def clear_event_mask(self):
- await self.__adapter_stub.ClearEventMask(empty_proto.Empty())
-
- async def clear_filter_accept_list(self):
- await self.__adapter_stub.ClearFilterAcceptList(empty_proto.Empty())
-
- async def disconnect_all_acls(self):
- await self.__adapter_stub.DisconnectAllAcls(empty_proto.Empty())
-
- async def le_rand(self):
- await self.__adapter_stub.LeRand(empty_proto.Empty())
- future = await self._listen_for_event(facade_pb2.EventType.LE_RAND)
- params = future.result()
- return params["data"].data[0]
-
- async def restore_filter_accept_list(self):
- await self.__adapter_stub.RestoreFilterAcceptList(empty_proto.Empty())
-
- async def set_default_event_mask_except(self, mask, le_mask):
- await self.__adapter_stub.SetDefaultEventMaskExcept(
- facade_pb2.SetDefaultEventMaskExceptRequest(mask=mask, le_mask=le_mask))
-
- async def set_event_filter_inquiry_result_all_devices(self):
- await self.__adapter_stub.SetEventFilterInquiryResultAllDevices(empty_proto.Empty())
-
- async def set_event_filter_connection_setup_all_devices(self):
- await self.__adapter_stub.SetEventFilterConnectionSetupAllDevices(empty_proto.Empty())
-
- async def allow_wake_by_hid(self):
- await self.__adapter_stub.AllowWakeByHid(empty_proto.Empty())
-
- async def set_local_io_caps(self, io_capability):
- await self.__adapter_stub.SetLocalIoCaps(facade_pb2.SetLocalIoCapsRequest(io_capability=io_capability))
- return await self._listen_for_event(facade_pb2.EventType.ADAPTER_PROPERTY)
-
- async def toggle_discovery(self, is_start):
- await self.__adapter_stub.ToggleDiscovery(facade_pb2.ToggleDiscoveryRequest(is_start=is_start))
- future = await self._listen_for_event(facade_pb2.EventType.DISCOVERY_STATE)
- return future
-
- async def find_device(self):
- return await self._listen_for_event(facade_pb2.EventType.DEVICE_FOUND)
-
-
-class A2dpAutomationHelper():
- """Invoke gRPC on topshim for A2DP testing"""
-
- def __init__(self, port=8999):
- self.__channel = grpc.insecure_channel("localhost:%d" % port)
- self.media_stub = facade_pb2_grpc.MediaServiceStub(self.__channel)
-
- """Start A2dp source profile service"""
-
- def start_source(self):
- self.media_stub.StartA2dp(facade_pb2.StartA2dpRequest(start_a2dp_source=True))
-
- """Start A2dp sink profile service"""
-
- def start_sink(self):
- self.media_stub.StartA2dp(facade_pb2.StartA2dpRequest(start_a2dp_sink=True))
-
- """Initialize an A2dp connection from source to sink"""
-
- def source_connect_to_remote(self, address="11:22:33:44:55:66"):
- self.media_stub.A2dpSourceConnect(facade_pb2.A2dpSourceConnectRequest(address=address))
diff --git a/system/blueberry/tests/topshim/lib/async_closable.py b/system/blueberry/tests/topshim/lib/async_closable.py
deleted file mode 100644
index 5eea802d68..0000000000
--- a/system/blueberry/tests/topshim/lib/async_closable.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-import asyncio
-import time
-from abc import ABC, abstractmethod
-import logging
-
-
-class AsyncClosable(ABC):
-
- async def __async_exit(self, type=None, value=None, traceback=None):
- try:
- return await self.close()
- except Exception:
- logging.warning("Failed to close or already closed")
-
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- asyncio.run_until_complete(self.__async_exit(type, value, traceback))
- return traceback is None
-
- def __del__(self):
- asyncio.get_event_loop().run_until_complete(self.__async_exit())
-
- @abstractmethod
- async def close(self):
- pass
-
-
-async def asyncSafeClose(closable):
- if closable is None:
- logging.warn("Tried to close an object that is None")
- return
- await closable.close()
diff --git a/system/blueberry/tests/topshim/lib/gatt_client.py b/system/blueberry/tests/topshim/lib/gatt_client.py
deleted file mode 100644
index dcd0b8b7a9..0000000000
--- a/system/blueberry/tests/topshim/lib/gatt_client.py
+++ /dev/null
@@ -1,385 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-import asyncio
-import grpc
-
-from blueberry.facade.topshim import facade_pb2
-from blueberry.facade.topshim import facade_pb2_grpc
-from blueberry.tests.topshim.lib.async_closable import AsyncClosable
-from blueberry.tests.topshim.lib.async_closable import asyncSafeClose
-
-from google.protobuf import empty_pb2 as empty_proto
-
-
-class GattClient(AsyncClosable):
- """
- Wrapper gRPC interface to the GATT Service
- """
- # Timeout for async wait
- DEFAULT_TIMEOUT = 2
- __task_list = []
- __channel = None
- __gatt_stub = None
- __adapter_event_stream = None
-
- def __init__(self, port=8999):
- self.__channel = grpc.aio.insecure_channel("localhost:%d" % port)
- self.__gatt_stub = facade_pb2_grpc.GattServiceStub(self.__channel)
- #self.__gatt_event_stream = self.__gatt_stub.FetchEvents(facade_pb2.FetchEventsRequest())
-
- async def close(self):
- """
- Terminate the current tasks
- """
- for task in self.__task_list:
- task.cancel()
- task = None
- self.__task_list.clear()
- await self.__channel.close()
-
- async def register_advertiser(self):
- """
- """
- await self.__gatt_stub.RegisterAdvertiser(empty_proto.Empty())
-
- async def unregister_advertiser(self, advertiser_id):
- """
- Stop advertising for advertiser id
- """
- # TODO(optedoblivion): make message to pass advertiser id
- await self.__gatt_stub.UnregisterAdvertiser(empty_proto.Empty())
-
- async def get_own_address(self):
- """
- """
- await self.__gatt_stub.GetOwnAddress(empty_proto.Empty())
-
- async def set_parameters(self):
- """
- """
- await self.__gatt_stub.SetParameters(empty_proto.Empty())
-
- async def set_data(self):
- """
- """
- await self.__gatt_stub.SetData(empty_proto.Empty())
-
- async def advertising_enable(self):
- """
- """
- await self.__gatt_stub.AdvertisingEnable(empty_proto.Empty())
-
- async def advertising_disable(self):
- """
- """
- await self.__gatt_stub.AdvertisingDisable(empty_proto.Empty())
-
- async def set_periodic_advertising_parameters(self):
- """
- """
- await self.__gatt_stub.SetPeriodicAdvertisingParameters(empty_proto.Empty())
-
- async def set_periodic_advertising_data(self):
- """
- """
- await self.__gatt_stub.SetPeriodicAdvertisingData(empty_proto.Empty())
-
- async def set_periodic_advertising_enable(self):
- """
- """
- await self.__gatt_stub.SetPeriodicAdvertisingEnable(empty_proto.Empty())
-
- async def start_advertising(self):
- """
- """
- await self.__gatt_stub.StartAdvertising(empty_proto.Empty())
-
- async def start_advertising_set(self):
- """
- Start advertising with the given parameters
- """
- await self.__gatt_stub.StartAdvertisingSet(empty_proto.Empty())
-
- async def register_scanner(self):
- """
- """
- await self.__gatt_stub.RegisterScanner(empty_proto.Empty())
-
- async def unregister_scanner(self):
- """
- """
- await self.__gatt_stub.UnregisterScanner(empty_proto.Empty())
-
- async def start_scan(self):
- """
- """
- await self.__gatt_stub.StartScan(empty_proto.Empty())
-
- async def stop_scan(self):
- """
- """
- await self.__gatt_stub.StopScan(empty_proto.Empty())
-
- async def scan_filter_setup(self):
- """
- """
- await self.__gatt_stub.ScanFilterSetup(empty_proto.Empty())
-
- async def scan_filter_add(self):
- """
- """
- await self.__gatt_stub.ScanFilterAdd(empty_proto.Empty())
-
- async def scan_filter_clear(self):
- """
- """
- await self.__gatt_stub.ScanFilterClear(empty_proto.Empty())
-
- async def scan_filter_enable(self):
- """
- """
- await self.__gatt_stub.ScanFilterEnable(empty_proto.Empty())
-
- async def scan_filter_disable(self):
- """
- """
- await self.__gatt_stub.ScanFilterDisable(empty_proto.Empty())
-
- async def set_scan_parameters(self):
- """
- """
- await self.__gatt_stub.SetScanParameters(empty_proto.Empty())
-
- async def batch_scan_config_storage(self):
- """
- """
- await self.__gatt_stub.BatchScanConfigStorage(empty_proto.Empty())
-
- async def batch_scan_enable(self):
- """
- """
- await self.__gatt_stub.BatchScanEnable(empty_proto.Empty())
-
- async def batch_scan_disable(self):
- """
- """
- await self.__gatt_stub.BatchScanDisable(empty_proto.Empty())
-
- async def batch_scan_read_reports(self):
- """
- """
- await self.__gatt_stub.BatchScanReadReports(empty_proto.Empty())
-
- async def start_sync(self):
- """
- """
- await self.__gatt_stub.StartSync(empty_proto.Empty())
-
- async def stop_sync(self):
- """
- """
- await self.__gatt_stub.StopSync(empty_proto.Empty())
-
- async def cancel_create_sync(self):
- """
- """
- await self.__gatt_stub.CancelCreateSync(empty_proto.Empty())
-
- async def transfer_sync(self):
- """
- """
- await self.__gatt_stub.TransferSync(empty_proto.Empty())
-
- async def transfer_set_info(self):
- """
- """
- await self.__gatt_stub.TransferSetInfo(empty_proto.Empty())
-
- async def sync_tx_parameters(self):
- """
- """
- await self.__gatt_stub.SyncTxParameters(empty_proto.Empty())
-
- async def register_client(self):
- """
- """
- await self.__gatt_stub.RegisterClient(empty_proto.Empty())
-
- async def unregister_client(self):
- """
- """
- await self.__gatt_stub.UnregisterClient(empty_proto.Empty())
-
- async def connect(self):
- """
- """
- await self.__gatt_stub.Connect(empty_proto.Empty())
-
- async def disconnect(self):
- """
- """
- await self.__gatt_stub.Disconnect(empty_proto.Empty())
-
- async def refresh(self):
- """
- """
- await self.__gatt_stub.Refresh(empty_proto.Empty())
-
- async def search_service(self):
- """
- """
- await self.__gatt_stub.SearchService(empty_proto.Empty())
-
- async def btif_gattc_discover_service_by_uuid(self):
- """
- """
- await self.__gatt_stub.BtifGattcDiscoverServiceByUuid(empty_proto.Empty())
-
- async def read_characteristic(self):
- """
- """
- await self.__gatt_stub.ReadCharacteristic(empty_proto.Empty())
-
- async def read_using_characteristic_uuid(self):
- """
- """
- await self.__gatt_stub.ReadUsingCharacteristicUuid(empty_proto.Empty())
-
- async def write_characteristic(self):
- """
- """
- await self.__gatt_stub.WriteCharacteristic(empty_proto.Empty())
-
- async def read_descriptor(self):
- """
- """
- await self.__gatt_stub.ReadDescriptor(empty_proto.Empty())
-
- async def write_descriptor(self):
- """
- """
- await self.__gatt_stub.WriteDescriptor(empty_proto.Empty())
-
- async def execute_write(self):
- """
- """
- await self.__gatt_stub.ExecuteWrite(empty_proto.Empty())
-
- async def register_for_notification(self):
- """
- """
- await self.__gatt_stub.RegisterForNotification(empty_proto.Empty())
-
- async def deregister_for_notification(self):
- """
- """
- await self.__gatt_stub.DeregisterForNotification(empty_proto.Empty())
-
- async def read_remote_rssi(self):
- """
- """
- await self.__gatt_stub.ReadRemoteRssi(empty_proto.Empty())
-
- async def get_device_type(self):
- """
- """
- await self.__gatt_stub.GetDeviceType(empty_proto.Empty())
-
- async def configure_mtu(self):
- """
- """
- await self.__gatt_stub.ConfigureMtu(empty_proto.Empty())
-
- async def conn_parameter_update(self):
- """
- """
- await self.__gatt_stub.ConnParameterUpdate(empty_proto.Empty())
-
- async def set_preferred_phy(self):
- """
- """
- await self.__gatt_stub.SetPreferredPhy(empty_proto.Empty())
-
- async def read_phy(self):
- """
- """
- await self.__gatt_stub.ReadPhy(empty_proto.Empty())
-
- async def test_command(self):
- """
- """
- await self.__gatt_stub.TestCommand(empty_proto.Empty())
-
- async def get_gatt_db(self):
- """
- """
- await self.__gatt_stub.GetGattDb(empty_proto.Empty())
-
- async def register_server(self):
- """
- """
- await self.__gatt_stub.RegisterServer(empty_proto.Empty())
-
- async def unregister_server(self):
- """
- """
- await self.__gatt_stub.UnregisterServer(empty_proto.Empty())
-
- async def connect(self):
- """
- """
- await self.__gatt_stub.Connect(empty_proto.Empty())
-
- async def disconnect(self):
- """
- """
- await self.__gatt_stub.Disconnect(empty_proto.Empty())
-
- async def add_service(self):
- """
- """
- await self.__gatt_stub.AddService(empty_proto.Empty())
-
- async def stop_service(self):
- """
- """
- await self.__gatt_stub.StopService(empty_proto.Empty())
-
- async def delete_service(self):
- """
- """
- await self.__gatt_stub.DeleteService(empty_proto.Empty())
-
- async def send_indication(self):
- """
- """
- await self.__gatt_stub.SendIndication(empty_proto.Empty())
-
- async def send_response(self):
- """
- """
- await self.__gatt_stub.SendResponse(empty_proto.Empty())
-
- async def set_preferred_phy(self):
- """
- """
- await self.__gatt_stub.SetPreferredPhy(empty_proto.Empty())
-
- async def read_phy(self):
- """
- """
- await self.__gatt_stub.ReadPhy(empty_proto.Empty())
diff --git a/system/blueberry/tests/topshim/lib/hf_client_client.py b/system/blueberry/tests/topshim/lib/hf_client_client.py
deleted file mode 100644
index 23d4832375..0000000000
--- a/system/blueberry/tests/topshim/lib/hf_client_client.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-import asyncio
-import grpc
-
-from blueberry.facade.topshim import facade_pb2
-from blueberry.facade.topshim import facade_pb2_grpc
-from blueberry.tests.topshim.lib.async_closable import AsyncClosable
-
-
-class HfClientClient(AsyncClosable):
- """
- Wrapper gRPC interface to the HF Client Service
- """
- __channel = None
- __hf_client_stub = None
-
- def __init__(self, port=8999):
- self.__channel = grpc.aio.insecure_channel("localhost:%d" % port)
- self.__hf_client_stub = facade_pb2_grpc.HfClientServiceStub(self.__channel)
-
- async def close(self):
- await self.__channel.close()
-
- async def start_slc(self, address):
- """
- """
- await self.__hf_client_stub.StartSlc(
- facade_pb2.StartSlcRequest(connection=facade_pb2.Connection(cookie=address.encode())))
-
- async def stop_slc(self, address):
- """
- """
- await self.__hf_client_stub.StopSlc(
- facade_pb2.StopSlcRequest(connection=facade_pb2.Connection(cookie=address.encode())))
-
- async def connect_audio(self, address):
- """
- """
- await self.__hf_client_stub.ConnectAudio(
- facade_pb2.ConnectAudioRequest(connection=facade_pb2.Connection(cookie=address.encode())))
-
- async def disconnect_audio(self, address):
- """
- """
- await self.__hf_client_stub.DisconnectAudio(
- facade_pb2.DisconnectAudioRequest(connection=facade_pb2.Connection(cookie=address.encode())))
diff --git a/system/blueberry/tests/topshim/lib/hfp_client.py b/system/blueberry/tests/topshim/lib/hfp_client.py
deleted file mode 100644
index c4bfd80f8a..0000000000
--- a/system/blueberry/tests/topshim/lib/hfp_client.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-import asyncio
-import grpc
-
-from blueberry.facade.topshim import facade_pb2
-from blueberry.facade.topshim import facade_pb2_grpc
-from blueberry.tests.topshim.lib.async_closable import AsyncClosable
-
-from google.protobuf import empty_pb2 as empty_proto
-
-
-class HfpClient(AsyncClosable):
- """
- Wrapper gRPC interface to the HFP Service
- """
- # Timeout for async wait
- DEFAULT_TIMEOUT = 2
- __task_list = []
- __channel = None
- __hfp_stub = None
- __hfp_event_stream = None
-
- def __init__(self, port=8999):
- self.__channel = grpc.aio.insecure_channel("localhost:%d" % port)
- self.__hfp_stub = facade_pb2_grpc.HfpServiceStub(self.__channel)
- self.__hfp_event_stream = self.__hfp_stub.FetchEvents(facade_pb2.FetchEventsRequest())
-
- async def close(self):
- """
- Terminate the current tasks.
- """
- for task in self.__task_list:
- task.cancel()
- task = None
- self.__task_list.clear()
- await self.__channel.close()
-
- async def start_slc(self, address):
- """
- """
- await self.__hfp_stub.StartSlc(
- facade_pb2.StartSlcRequest(connection=facade_pb2.Connection(cookie=address.encode())))
- return await self._listen_for_event(facade_pb2.EventType.HFP_CONNECTION_STATE)
-
- async def stop_slc(self, address):
- """
- """
- await self.__hfp_stub.StopSlc(
- facade_pb2.StopSlcRequest(connection=facade_pb2.Connection(cookie=address.encode())))
- return await self._listen_for_event(facade_pb2.EventType.HFP_CONNECTION_STATE)
-
- async def connect_audio(self, address, is_sco_offload_enabled=False, disabled_codecs=0):
- """
- """
- await self.__hfp_stub.ConnectAudio(
- facade_pb2.ConnectAudioRequest(connection=facade_pb2.Connection(cookie=address.encode()),
- is_sco_offload_enabled=is_sco_offload_enabled,
- disabled_codecs=disabled_codecs))
-
- async def disconnect_audio(self, address):
- """
- """
- await self.__hfp_stub.DisconnectAudio(
- facade_pb2.DisconnectAudioRequest(connection=facade_pb2.Connection(cookie=address.encode())))
-
- async def set_volume(self, address, volume):
- """
- """
- await self.__hfp_stub.DisconnectAudio(
- facade_pb2.DisconnectAudioRequest(connection=facade_pb2.Connection(cookie=address.encode()), volume=volume))
-
- async def wait_for_hfp_connection_state_change(self):
- return await self._listen_for_event(facade_pb2.EventType.HFP_CONNECTION_STATE)
-
- async def __get_next_event(self, event, future):
- """Get the future of next event from the stream"""
- while True:
- e = await self.__hfp_event_stream.read()
-
- # Match event by some condition.
- if e.event_type == event:
- future.set_result(e.data)
- break
- else:
- print("Got '%s'; expecting '%s'" % (e.event_type, event))
- print(e)
-
- async def _listen_for_event(self, event):
- """Start fetching events"""
- future = asyncio.get_running_loop().create_future()
- self.__task_list.append(asyncio.get_running_loop().create_task(self.__get_next_event(event, future)))
- try:
- await asyncio.wait_for(future, HfpClient.DEFAULT_TIMEOUT)
- except:
- print("Failed to get event", event)
- return future
diff --git a/system/blueberry/tests/topshim/lib/oob_data.py b/system/blueberry/tests/topshim/lib/oob_data.py
deleted file mode 100644
index 0ec9ff7c4c..0000000000
--- a/system/blueberry/tests/topshim/lib/oob_data.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-
-class OobData:
- """
- Represents an Out of Band data set in a readible object
- """
-
- def __init__(self, is_valid, transport, byte_string_address, byte_string_c, byte_string_r):
- """
- @param is_valid indicates whether the data was able to be parsed
- @param transport LE or Classic
- @param 7 octet byte string. Little Endian 6 byte address + 1 byte transport
- @param byte_string_c 16 octet confirmation
- @param byte_string_r 16 octet randomizer
- """
- self.__is_valid = True if is_valid == "1" else False
- self.__transport = int(transport)
- self.__byte_string_address = byte_string_address
- self.__byte_string_c = byte_string_c
- self.__byte_string_r = byte_string_r
-
- def is_valid(self):
- return self.__is_valid
-
- def transport(self):
- return self.__transport
-
- def address(self):
- return self.__byte_string_address
-
- def confirmation(self):
- return self.__byte_string_c
-
- def randomizer(self):
- return self.__byte_string_r
diff --git a/system/blueberry/tests/topshim/lib/security_client.py b/system/blueberry/tests/topshim/lib/security_client.py
deleted file mode 100644
index f22550e564..0000000000
--- a/system/blueberry/tests/topshim/lib/security_client.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-import grpc
-
-from blueberry.facade.topshim import facade_pb2
-from blueberry.facade.topshim import facade_pb2_grpc
-from blueberry.tests.topshim.lib.async_closable import AsyncClosable
-from blueberry.tests.topshim.lib.async_closable import asyncSafeClose
-
-from google.protobuf import empty_pb2 as empty_proto
-
-
-class SecurityClient(AsyncClosable):
- """
- Wrapper gRPC interface to the GATT Service
- """
- # Timeout for async wait
- __task_list = []
- __channel = None
- __security = None
- __adapter = None
-
- def __init__(self, adapter, port=8999):
- self.__channel = grpc.aio.insecure_channel("localhost:%d" % port)
- self.__security = facade_pb2_grpc.SecurityServiceStub(self.__channel)
- self.__adapter = adapter
-
- async def close(self):
- """
- Terminate the current tasks
- """
- for task in self.__task_list:
- task.cancel()
- task = None
- self.__task_list.clear()
- await self.__channel.close()
-
- async def create_bond(self, address, transport):
- """
- Create a bonding entry for a given address with a particular transport type
- """
- await self.__security.CreateBond(facade_pb2.CreateBondRequest(address=address, transport=transport))
- # State change to Bonding
- await self.__adapter._listen_for_event(facade_pb2.EventType.BOND_STATE)
- # State change to Bonded or None (based on success and failure)
- return await self.__adapter._listen_for_event(facade_pb2.EventType.BOND_STATE)
-
- async def remove_bond(self, address):
- """
- Removes a bonding entry for a given address
- """
- await self.__security.RemoveBond(facade_pb2.RemoveBondRequest(address=address))
-
- async def generate_local_oob_data(self, transport):
- await self.__security.GenerateLocalOobData(facade_pb2.GenerateOobDataRequest(transport=transport))
- future = await self.__adapter._listen_for_event(facade_pb2.EventType.GENERATE_LOCAL_OOB_DATA)
- return future
diff --git a/system/blueberry/tests/topshim/lib/topshim_base_test.py b/system/blueberry/tests/topshim/lib/topshim_base_test.py
deleted file mode 100644
index 00c9f03eaa..0000000000
--- a/system/blueberry/tests/topshim/lib/topshim_base_test.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-import asyncio
-import importlib
-import logging
-import os
-import signal
-import subprocess
-
-from blueberry.tests.gd.cert.async_subprocess_logger import AsyncSubprocessLogger
-from blueberry.tests.gd.cert.context import get_current_context
-from blueberry.tests.gd.cert.os_utils import get_gd_root
-from blueberry.tests.gd.cert.os_utils import get_gd_root
-from blueberry.tests.gd.cert.os_utils import read_crash_snippet_and_log_tail
-from blueberry.tests.gd.cert.os_utils import is_subprocess_alive
-from blueberry.tests.gd.cert.os_utils import make_ports_available
-from blueberry.tests.gd.cert.os_utils import TerminalColor
-from blueberry.tests.gd.cert.tracelogger import TraceLogger
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.topshim.lib.adapter_client import AdapterClient
-from blueberry.tests.topshim.lib.async_closable import asyncSafeClose
-from blueberry.tests.topshim.lib.gatt_client import GattClient
-from blueberry.tests.topshim.lib.hf_client_client import HfClientClient
-from blueberry.tests.topshim.lib.hfp_client import HfpClient
-from blueberry.tests.topshim.lib.security_client import SecurityClient
-from blueberry.tests.topshim.lib.topshim_device import TopshimDevice
-
-from mobly import asserts
-from mobly import base_test
-
-CONTROLLER_CONFIG_NAME = "GdDevice"
-
-
-def _setup_class_core(verbose_mode, log_path_base, controller_configs):
- info = {}
- info['controller_configs'] = controller_configs
-
- # Start root-canal if needed
- info['rootcanal_running'] = False
- info['rootcanal_logpath'] = None
- info['rootcanal_process'] = None
- info['rootcanal_logger'] = None
- if 'rootcanal' not in info['controller_configs']:
- return
- info['rootcanal_running'] = True
- # Get root canal binary
- rootcanal = os.path.join(get_gd_root(), "root-canal")
- info['rootcanal'] = rootcanal
- info['rootcanal_exist'] = os.path.isfile(rootcanal)
- if not os.path.isfile(rootcanal):
- return info
- # Get root canal log
- rootcanal_logpath = os.path.join(log_path_base, 'rootcanal_logs.txt')
- info['rootcanal_logpath'] = rootcanal_logpath
- # Make sure ports are available
- rootcanal_config = info['controller_configs']['rootcanal']
- rootcanal_test_port = int(rootcanal_config.get("test_port", "6401"))
- rootcanal_hci_port = int(rootcanal_config.get("hci_port", "6402"))
- rootcanal_link_layer_port = int(rootcanal_config.get("link_layer_port", "6403"))
-
- info['make_rootcanal_ports_available'] = make_ports_available(
- (rootcanal_test_port, rootcanal_hci_port, rootcanal_link_layer_port))
- if not make_ports_available((rootcanal_test_port, rootcanal_hci_port, rootcanal_link_layer_port)):
- return info
-
- # Start root canal process
- rootcanal_cmd = [rootcanal, str(rootcanal_test_port), str(rootcanal_hci_port), str(rootcanal_link_layer_port)]
- info['rootcanal_cmd'] = rootcanal_cmd
-
- rootcanal_process = subprocess.Popen(rootcanal_cmd,
- cwd=get_gd_root(),
- env=os.environ.copy(),
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
-
- info['rootcanal_process'] = rootcanal_process
- if rootcanal_process:
- info['is_rootcanal_process_started'] = True
- else:
- info['is_rootcanal_process_started'] = False
- return info
- info['is_subprocess_alive'] = is_subprocess_alive(rootcanal_process)
- if not is_subprocess_alive(rootcanal_process):
- info['is_subprocess_alive'] = False
- return info
-
- info['rootcanal_logger'] = AsyncSubprocessLogger(rootcanal_process, [rootcanal_logpath],
- log_to_stdout=verbose_mode,
- tag="rootcanal",
- color=TerminalColor.MAGENTA)
-
- # Modify the device config to include the correct root-canal port
- for gd_device_config in info['controller_configs'].get("GdDevice"):
- gd_device_config["rootcanal_port"] = str(rootcanal_hci_port)
-
- return info
-
-
-def _teardown_class_core(rootcanal_running, rootcanal_process, rootcanal_logger, subprocess_wait_timeout_seconds):
- if rootcanal_running:
- stop_signal = signal.SIGINT
- rootcanal_process.send_signal(stop_signal)
- try:
- return_code = rootcanal_process.wait(timeout=subprocess_wait_timeout_seconds)
- except subprocess.TimeoutExpired:
- logging.error("Failed to interrupt root canal via SIGINT, sending SIGKILL")
- stop_signal = signal.SIGKILL
- rootcanal_process.kill()
- try:
- return_code = rootcanal_process.wait(timeout=subprocess_wait_timeout_seconds)
- except subprocess.TimeoutExpired:
- logging.error("Failed to kill root canal")
- return_code = -65536
- if return_code != 0 and return_code != -stop_signal:
- logging.error("rootcanal stopped with code: %d" % return_code)
- rootcanal_logger.stop()
-
-
-def dump_crashes_core(dut, cert, rootcanal_running, rootcanal_process, rootcanal_logpath):
- dut_crash, dut_log_tail = dut.get_crash_snippet_and_log_tail()
- cert_crash, cert_log_tail = cert.get_crash_snippet_and_log_tail()
- rootcanal_crash = None
- rootcanal_log_tail = None
- if rootcanal_running and not is_subprocess_alive(rootcanal_process):
- rootcanal_crash, roocanal_log_tail = read_crash_snippet_and_log_tail(rootcanal_logpath)
-
- crash_detail = ""
- if dut_crash or cert_crash or rootcanal_crash:
- if rootcanal_crash:
- crash_detail += "rootcanal crashed:\n\n%s\n\n" % rootcanal_crash
- if dut_crash:
- crash_detail += "dut stack crashed:\n\n%s\n\n" % dut_crash
- if cert_crash:
- crash_detail += "cert stack crashed:\n\n%s\n\n" % cert_crash
- else:
- if rootcanal_log_tail:
- crash_detail += "rootcanal log tail:\n\n%s\n\n" % rootcanal_log_tail
- if dut_log_tail:
- crash_detail += "dut log tail:\n\n%s\n\n" % dut_log_tail
- if cert_log_tail:
- crash_detail += "cert log tail:\n\n%s\n\n" % cert_log_tail
-
- return crash_detail
-
-
-class TopshimBaseTest(base_test.BaseTestClass):
-
- __dut = None
- __cert = None
-
- async def __setup_adapter(self):
- dut_adapter = AdapterClient(port=self.dut_port)
- cert_adapter = AdapterClient(port=self.cert_port)
- started = await dut_adapter._verify_adapter_started()
- assertThat(started).isTrue()
- started = started and await cert_adapter._verify_adapter_started()
- assertThat(started).isTrue()
- self.__dut = TopshimDevice(dut_adapter, GattClient(port=self.dut_port),
- SecurityClient(dut_adapter, port=self.dut_port),
- HfpClient(port=self.dut_port),
- HfClientClient(port=self.dut_port))
- self.__cert = TopshimDevice(cert_adapter, GattClient(port=self.cert_port),
- SecurityClient(cert_adapter, port=self.cert_port),
- HfpClient(port=self.cert_port),
- HfClientClient(port=self.cert_port))
- return started
-
- async def __teardown_adapter(self):
- await asyncSafeClose(self.__dut)
- await asyncSafeClose(self.__cert)
-
- def dut(self):
- """
- Get a handle on the DUT device
- """
- return self.__dut
-
- def cert(self):
- """
- Get a handle on the CERT device
- """
- return self.__cert
-
- def setup_class(self):
- """
- Configure rootcanal and setup test parameters
- """
- self.log = TraceLogger(logging.getLogger())
- self.log_path_base = get_current_context().get_full_output_path()
- self.verbose_mode = bool(self.user_params.get('verbose_mode', False))
- for config in self.controller_configs[CONTROLLER_CONFIG_NAME]:
- config['verbose_mode'] = self.verbose_mode
-
- self.info = _setup_class_core(verbose_mode=self.verbose_mode,
- log_path_base=self.log_path_base,
- controller_configs=self.controller_configs)
- self.rootcanal_running = self.info['rootcanal_running']
- self.rootcanal_logpath = self.info['rootcanal_logpath']
- self.rootcanal_process = self.info['rootcanal_process']
- self.rootcanal_logger = self.info['rootcanal_logger']
-
- asserts.assert_true(self.info['rootcanal_exist'], "Root canal does not exist at %s" % self.info['rootcanal'])
- asserts.assert_true(self.info['make_rootcanal_ports_available'], "Failed to make root canal ports available")
-
- self.log.debug("Running %s" % " ".join(self.info['rootcanal_cmd']))
- asserts.assert_true(self.info['is_rootcanal_process_started'],
- msg="Cannot start root-canal at " + str(self.info['rootcanal']))
- asserts.assert_true(self.info['is_subprocess_alive'], msg="root-canal stopped immediately after running")
-
- self.controller_configs = self.info['controller_configs']
-
- controllers = self.register_controller(importlib.import_module('blueberry.tests.topshim.lib.topshim_device'))
- self.cert_port = controllers[0].grpc_port
- self.dut_port = controllers[1].grpc_port
- asyncio.set_event_loop(asyncio.new_event_loop())
- asyncio.get_event_loop().run_until_complete(self.__setup_adapter())
-
- def teardown_class(self):
- _teardown_class_core(rootcanal_running=self.rootcanal_running,
- rootcanal_process=self.rootcanal_process,
- rootcanal_logger=self.rootcanal_logger,
- subprocess_wait_timeout_seconds=1)
- asyncio.get_event_loop().run_until_complete(self.__teardown_adapter())
diff --git a/system/blueberry/tests/topshim/lib/topshim_device.py b/system/blueberry/tests/topshim/lib/topshim_device.py
deleted file mode 100644
index b845f48174..0000000000
--- a/system/blueberry/tests/topshim/lib/topshim_device.py
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2019 - 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.
-
-import asyncio
-import logging
-
-from blueberry.tests.gd.cert.gd_device import GdHostOnlyDevice
-from blueberry.tests.gd.cert.gd_device import MOBLY_CONTROLLER_CONFIG_NAME
-from blueberry.tests.gd.cert.os_utils import get_gd_root
-from blueberry.tests.topshim.lib.async_closable import AsyncClosable
-from blueberry.tests.topshim.lib.async_closable import asyncSafeClose
-from blueberry.tests.topshim.lib.oob_data import OobData
-from blueberry.tests.topshim.lib.gatt_client import GattClient
-
-
-def create(configs):
- return get_instances_with_configs(configs)
-
-
-def destroy(devices):
- pass
-
-
-def replace_vars_for_topshim(string, config):
- serial_number = config.get("serial_number")
- if serial_number is None:
- serial_number = ""
- rootcanal_port = config.get("rootcanal_port")
- if rootcanal_port is None:
- rootcanal_port = ""
- if serial_number == "DUT" or serial_number == "CERT":
- raise Exception("Did you forget to configure the serial number?")
- # We run bt_topshim_facade instead of bluetooth_stack_with_facade
- return string.replace("$GD_ROOT", get_gd_root()) \
- .replace("bluetooth_stack_with_facade", "bt_topshim_facade") \
- .replace("$(grpc_port)", config.get("grpc_port")) \
- .replace("$(grpc_root_server_port)", config.get("grpc_root_server_port")) \
- .replace("$(rootcanal_port)", rootcanal_port) \
- .replace("$(signal_port)", config.get("signal_port")) \
- .replace("$(serial_number)", serial_number)
-
-
-def get_instances_with_configs(configs):
- logging.info(configs)
- devices = []
- for config in configs:
- resolved_cmd = []
- for arg in config["cmd"]:
- logging.debug(arg)
- resolved_cmd.append(replace_vars_for_topshim(arg, config))
- verbose_mode = bool(config.get('verbose_mode', False))
- device = GdHostOnlyDevice(config["grpc_port"], "-1", config["signal_port"], resolved_cmd, config["label"],
- MOBLY_CONTROLLER_CONFIG_NAME, config["name"], verbose_mode)
- device.setup()
- devices.append(device)
- return devices
-
-
-TRANSPORT_CLASSIC = 1
-TRANSPORT_LE = 2
-
-
-class TopshimDevice(AsyncClosable):
- __adapter = None
- __gatt = None
- __security = None
- __hfp = None
- __hf_client = None
-
- async def __le_rand_wrapper(self, async_fn):
- result = await async_fn
- await self.__adapter.le_rand()
- le_rand_future = await self.__adapter._listen_for_event(facade_pb2.EventType.LE_RAND)
- return result
-
- def __post(self, async_fn):
- return asyncio.get_event_loop().run_until_complete(async_fn)
-
- def __init__(self, adapter, gatt, security, hfp, hf_client):
- self.__adapter = adapter
- self.__gatt = gatt
- self.__security = security
- self.__hfp = hfp
- self.__hf_client = hf_client
-
- async def close(self):
- """
- Implement abstract method to close out any streams or jobs.
- """
- await asyncSafeClose(self.__adapter)
- await asyncSafeClose(self.__gatt)
- await asyncSafeClose(self.__security)
- await asyncSafeClose(self.__hfp)
- await asyncSafeClose(self.__hf_client)
-
- def enable_inquiry_scan(self):
- f = self.__post(self.__adapter.enable_inquiry_scan())
- return self.__post(self.__discovery_mode_waiter(f))
-
- def enable_page_scan(self):
- f = self.__post(self.__adapter.enable_page_scan())
- return self.__post(self.__discovery_mode_waiter(f))
-
- def disable_page_scan(self):
- f = self.__post(self.__adapter.disable_page_scan())
- return self.__post(self.__discovery_mode_waiter(f))
-
- async def __discovery_mode_waiter(self, f):
- params = await f
- status, discovery_mode = params["status"].data[0], params["AdapterScanMode"].data[0]
- return (status, discovery_mode)
-
- def start_advertising(self):
- """
- Starts BLE Advertiser for the stack.
- Assumes stack defaults. Which in our case would be RRPA
- """
- self.__post(self.__gatt.advertising_enable())
-
- def stop_advertising(self):
- """
- Stop BLE Advertiser.
- """
- self.__post(self.__gatt.advertising_disable())
-
- def start_scanning(self):
- pass
-
- def stop_scanning(self):
- pass
-
- def clear_event_mask(self):
- self.__post(self.__adapter.clear_event_mask())
-
- def clear_event_filter(self):
- self.__post(self.__adapter.clear_event_filter())
-
- def clear_filter_accept_list(self):
- self.__post(self.__adapter.clear_filter_accept_list())
-
- def disconnect_all_acls(self):
- self.__post(self.__adapter.disconnect_all_acls())
-
- def allow_wake_by_hid(self):
- self.__post(self.__adapter.allow_wake_by_hid())
-
- def set_default_event_mask_except(self, mask, le_mask):
- self.__post(self.__adapter.set_default_event_mask_except(mask, le_mask))
-
- def set_event_filter_inquiry_result_all_devices(self):
- self.__post(self.__adapter.set_event_filter_inquiry_result_all_devices())
-
- def set_event_filter_connection_setup_all_devices(self):
- self.__post(self.__adapter.set_event_filter_connection_setup_all_devices())
-
- def le_rand(self):
- self.__post(self.__adapter.le_rand())
-
- def create_bond(self, address, transport=1):
- """
- Create a bonding entry for a given address with a particular transport type.
- """
- f = self.__post(self.__security.create_bond(address, transport))
- return self.__post(self.__bond_change_waiter(f))
-
- def remove_bonded_device(self, address):
- """
- Removes a bonding entry for a given address.
- """
- self.__post(self.__security.remove_bond(address))
-
- async def __bond_change_waiter(self, f):
- params = await f
- state, address = params["bond_state"].data[0], params["address"].data[0]
- return (state, address)
-
- def generate_local_oob_data(self, transport=TRANSPORT_LE):
- """
- Generate local Out of Band data
-
- @param transport TRANSPORT_CLASSIC or TRANSPORT_LE
-
- @return a future to await on fo the data
- """
- f = self.__post(self.__security.generate_local_oob_data(transport))
-
- async def waiter(f):
- params = await f
- return OobData(params["is_valid"].data[0], params["transport"].data[0], params["address"].data[0],
- params["confirmation"].data[0], params["randomizer"].data[0])
-
- return self.__post(waiter(f))
-
- def set_local_io_caps(self, io_capability=0):
- f = self.__post(self.__adapter.set_local_io_caps(io_capability))
-
- async def waiter(f):
- params = await f
- status, io_caps = params["status"].data[0], params["LocalIoCaps"].data[0]
- return (status, io_caps)
-
- return self.__post(waiter(f))
-
- def toggle_discovery(self, is_start):
- f = self.__post(self.__adapter.toggle_discovery(is_start))
-
- async def waiter(f):
- params = await f
- return params["discovery_state"].data[0]
-
- return self.__post(waiter(f))
-
- def find_device(self):
- """
- Attempts to find discoverable devices when discovery is toggled on.
-
- @return a list of properties of found device.
- """
- f = self.__post(self.__adapter.find_device())
-
- async def waiter(f):
- try:
- params = await f
- return params["BdAddr"].data[0]
- except:
- # The future `f` has a timeout after 2s post which it is cancelled.
- print("No device was found. Timed out.")
- return None
-
- return self.__post(waiter(f))
-
- def start_slc(self, address):
- f = self.__post(self.__hfp.start_slc(address))
- return self.__post(self.__hfp_connection_state_waiter(f))
-
- def stop_slc(self, address):
- f = self.__post(self.__hfp.stop_slc(address))
- return self.__post(self.__hfp_connection_state_waiter(f))
-
- def wait_for_hfp_connection_state_change(self):
- f = self.__post(self.__hfp.wait_for_hfp_connection_state_change())
- return self.__post(self.__hfp_connection_state_waiter(f))
-
- async def __hfp_connection_state_waiter(self, f):
- data = await f
- data_list = data.split(", ")
- state, address = data_list[0].strip(), data_list[1].strip()
- return (state, address)
diff --git a/system/blueberry/tests/topshim/power/suspend_test.py b/system/blueberry/tests/topshim/power/suspend_test.py
deleted file mode 100644
index 4292c05459..0000000000
--- a/system/blueberry/tests/topshim/power/suspend_test.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.topshim.lib.topshim_base_test import TopshimBaseTest
-from blueberry.tests.topshim.lib.adapter_client import AdapterClient
-
-from mobly import test_runner
-
-
-class SuspendTest(TopshimBaseTest):
-
- def __verify_no_wake_suspend(self):
- # Start suspend work
- self.dut().clear_event_mask()
- self.dut().clear_event_filter()
- self.dut().clear_filter_accept_list()
- self.dut().stop_advertising()
- self.dut().stop_scanning()
- self.dut().disconnect_all_acls()
- self.dut().le_rand()
-
- def __verify_no_wake_resume(self):
- # Start resume work
- self.dut().set_default_event_mask_except(0, 0)
- self.dut().set_event_filter_inquiry_result_all_devices()
- self.dut().set_event_filter_connection_setup_all_devices()
- self.dut().le_rand()
-
- def __verify_wakeful_suspend(self, is_a2dp_connected):
- self.dut().clear_event_mask()
- self.dut().clear_event_filter()
- self.dut().clear_filter_accept_list()
- self.dut().stop_advertising()
- self.dut().stop_scanning()
- if is_a2dp_connected:
- # self.media_server.disconnect_a2dp()
- pass
- self.dut().disconnect_all_acls()
- self.dut().allow_wake_by_hid()
- self.dut().le_rand()
-
- def __verify_wakeful_resume(self, was_a2dp_connected):
- # Start resume work
- self.dut().set_default_event_mask_except(0, 0)
- self.dut().set_event_filter_inquiry_result_all_devices()
- self.dut().set_event_filter_connection_setup_all_devices()
- if was_a2dp_connected:
- # restore filter accept list?
- self.dut().restore_filter_accept_list()
- # reconnect a2dp
- # self.media_server.reconnect_last_a2dp()
- # self.gatt.restart_all_previous_advertising()
- self.dut().start_advertising()
- self.dut().le_rand()
-
- def test_no_wake_suspend(self):
- self.__verify_no_wake_suspend()
-
- def test_no_wake_resume(self):
- self.__verify_no_wake_resume()
-
- def test_no_wake_suspend_then_resume(self):
- self.__verify_no_wake_suspend()
- self.__verify_no_wake_resume()
-
- def test_no_wake_suspend_then_resume_then_suspend(self):
- self.__verify_no_wake_suspend()
- self.__verify_no_wake_resume()
- self.__verify_no_wake_suspend()
-
- def test_wakeful_suspend_no_a2dp(self):
- self.__verify_wakeful_suspend(False)
-
- def test_wakeful_resume_no_a2dp(self):
- self.__verify_wakeful_resume(False)
-
- def test_wakeful_suspend_then_resume_no_a2dp(self):
- self.__verify_wakeful_suspend(False)
- self.__verify_wakeful_resume(False)
-
- def test_wakeful_suspend_then_resume_then_suspend_no_a2dp(self):
- self.__verify_wakeful_suspend(False)
- self.__verify_wakeful_resume(False)
- self.__verify_wakeful_suspend(False)
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/system/blueberry/tests/topshim/security/classic_security_test.py b/system/blueberry/tests/topshim/security/classic_security_test.py
deleted file mode 100644
index b0bfab469d..0000000000
--- a/system/blueberry/tests/topshim/security/classic_security_test.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.topshim.lib.adapter_client import AdapterClient
-from blueberry.tests.topshim.lib.topshim_base_test import TopshimBaseTest
-from blueberry.tests.topshim.lib.topshim_device import TRANSPORT_CLASSIC
-
-from mobly import test_runner
-
-
-class ClassicSecurityTest(TopshimBaseTest):
-
- def test_create_classic_bond(self):
- self.dut().enable_inquiry_scan()
- self.cert().enable_inquiry_scan()
- self.dut().toggle_discovery(True)
- address = self.dut().find_device()
- state, conn_addr = self.dut().create_bond(address=address, transport=TRANSPORT_CLASSIC)
- assertThat(state).isEqualTo("Bonded")
- assertThat(conn_addr).isEqualTo(address)
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/system/blueberry/tests/topshim/security/le_security_test.py b/system/blueberry/tests/topshim/security/le_security_test.py
deleted file mode 100644
index 307c3ec429..0000000000
--- a/system/blueberry/tests/topshim/security/le_security_test.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-from blueberry.tests.gd.cert.truth import assertThat
-from blueberry.tests.topshim.lib.adapter_client import AdapterClient
-from blueberry.tests.topshim.lib.topshim_base_test import TopshimBaseTest
-from blueberry.tests.topshim.lib.topshim_device import TRANSPORT_CLASSIC, TRANSPORT_LE
-
-from mobly import test_runner
-
-
-class LeSecurityTest(TopshimBaseTest):
-
- DUMMY_ADDRESS = "01:02:03:04:05:06"
-
- def test_remove_bond_with_no_bonded_devices(self):
- self.dut().remove_bonded_device(self.DUMMY_ADDRESS)
- self.dut().le_rand()
-
- def test_generate_local_oob_data(self):
- oob_data = self.dut().generate_local_oob_data(TRANSPORT_CLASSIC)
- assertThat(oob_data.is_valid()).isTrue()
- oob_data = self.dut().generate_local_oob_data(TRANSPORT_LE)
- assertThat(oob_data.is_valid()).isTrue()
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/system/blueberry/tests/topshim/topshim_host_config.yaml b/system/blueberry/tests/topshim/topshim_host_config.yaml
deleted file mode 100644
index 15155db8d7..0000000000
--- a/system/blueberry/tests/topshim/topshim_host_config.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-_description: Bluetooth cert testing
-TestBeds:
- - Name: HostOnlyCert
- Controllers:
- rootcanal:
- test_port: '6401'
- hci_port: '6402'
- link_layer_port: '6403'
- GdDevice:
- - grpc_port: '8998'
- grpc_root_server_port: '8996'
- signal_port: '8994'
- label: cert
- name: Cert Device
- cmd:
- - "$GD_ROOT/bluetooth_stack_with_facade"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--rootcanal-port=$(rootcanal_port)"
- - "--signal-port=$(signal_port)"
- - grpc_port: '8999'
- grpc_root_server_port: '8997'
- signal_port: '8995'
- label: dut
- name: DUT Device
- cmd:
- - "$GD_ROOT/bluetooth_stack_with_facade"
- - "--grpc-port=$(grpc_port)"
- - "--root-server-port=$(grpc_root_server_port)"
- - "--rootcanal-port=$(rootcanal_port)"
- - "--signal-port=$(signal_port)"
-logpath: "/tmp/logs"
diff --git a/system/blueberry/tests/topshim/topshim_test_runner.py b/system/blueberry/tests/topshim/topshim_test_runner.py
deleted file mode 100644
index 115e078f97..0000000000
--- a/system/blueberry/tests/topshim/topshim_test_runner.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2022 - 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.
-
-from blueberry.tests.topshim.adapter.adapter_test import AdapterTest
-from blueberry.tests.topshim.hfp.hfp_test import HfpTest
-from blueberry.tests.topshim.power.suspend_test import SuspendTest
-from blueberry.tests.topshim.security.classic_security_test import ClassicSecurityTest
-from blueberry.tests.topshim.security.le_security_test import LeSecurityTest
-
-from mobly import suite_runner
-import argparse
-
-ALL_TESTS = [AdapterTest, ClassicSecurityTest, HfpTest, LeSecurityTest, SuspendTest]
-
-
-def main():
- """
- Local test runner that allows to specify list of tests to and customize
- test config file location
- """
- parser = argparse.ArgumentParser(description="Run local Topshim to Topshim tests.")
- parser.add_argument('-c',
- '--config',
- type=str,
- required=True,
- metavar='<PATH>',
- help='Path to the test configuration file.')
- parser.add_argument('--tests',
- '--test_case',
- nargs='+',
- type=str,
- metavar='[ClassA[.test_a] ClassB[.test_b] ...]',
- help='A list of test classes and optional tests to execute.')
- parser.add_argument("--all_tests", "-A", type=bool, dest="all_tests", default=False, nargs="?")
- parser.add_argument("--presubmit", type=bool, dest="presubmit", default=False, nargs="?")
- parser.add_argument("--postsubmit", type=bool, dest="postsubmit", default=False, nargs="?")
- args = parser.parse_args()
- test_list = ALL_TESTS
- if args.all_tests:
- test_list = ALL_TESTS
- elif args.presubmit:
- test_list = ALL_TESTS
- elif args.postsubmit:
- test_list = ALL_TESTS
- # Do not pass this layer's cmd line argument to next layer
- argv = ["--config", args.config]
- if args.tests:
- argv.append("--tests")
- for test in args.tests:
- argv.append(test)
-
- suite_runner.run_suite(test_list, argv=argv)
-
-
-if __name__ == "__main__":
- main()
diff --git a/system/bta/Android.bp b/system/bta/Android.bp
index f99f437bd4..efa1d25fd1 100644
--- a/system/bta/Android.bp
+++ b/system/bta/Android.bp
@@ -27,9 +27,6 @@ cc_defaults {
"packages/modules/Bluetooth/system/udrv/include",
],
header_libs: ["libbluetooth_headers"],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
}
filegroup {
@@ -238,7 +235,6 @@ cc_library_static {
cc_test {
name: "net_test_bta",
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_bta_defaults",
"latest_android_hardware_audio_common_ndk_static",
"latest_android_hardware_bluetooth_audio_ndk_static",
@@ -288,9 +284,6 @@ cc_test {
"test/bta_sdp_test.cc",
"test/bta_sec_test.cc",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
shared_libs: [
"libaconfig_storage_read_api_cc",
"libcrypto",
@@ -376,9 +369,6 @@ cc_test {
"test/gatt/database_builder_test.cc",
"test/gatt/database_test.cc",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
shared_libs: [
"libaconfig_storage_read_api_cc",
"libbase",
@@ -438,6 +428,7 @@ cc_test {
"libbluetooth_core_rs_bridge",
"libbluetooth_crypto_toolbox",
"libbluetooth_gd",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-audio-hal-interface",
"libbt-bta",
@@ -466,9 +457,6 @@ cc_test {
"packages/modules/Bluetooth/system",
"packages/modules/Bluetooth/system/gd",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":TestCommonMockFunctions",
":TestFakeOsi",
@@ -647,6 +635,7 @@ cc_test {
srcs: [
":TestCommonMockFunctions",
":TestMockStackBtmInterface",
+ ":TestMockStackGatt",
"gatt/database.cc",
"gatt/database_builder.cc",
"test/common/bta_gatt_api_mock.cc",
@@ -670,6 +659,7 @@ cc_test {
static_libs: [
"aics",
"bluetooth_flags_c_lib_for_test",
+ "libaconfig_storage_read_api_cc",
"libbluetooth-types",
"libbluetooth_crypto_toolbox",
"libbluetooth_gd",
@@ -764,7 +754,6 @@ cc_test {
test_suites: ["general-tests"],
defaults: [
"aconfig_lib_cc_shared_link.defaults",
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -811,7 +800,6 @@ cc_test {
":audio_set_scenarios_json",
],
generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
"LeAudioSetConfigSchemas_h",
],
shared_libs: [
@@ -823,6 +811,7 @@ cc_test {
],
static_libs: [
"bluetooth_flags_c_lib_for_test",
+ "libaconfig_storage_read_api_cc",
"libbluetooth-types",
"libbluetooth_crypto_toolbox",
"libbluetooth_gd",
@@ -848,7 +837,6 @@ cc_test {
name: "bluetooth_le_audio_test",
test_suites: ["general-tests"],
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -921,7 +909,6 @@ cc_test {
":audio_set_scenarios_json",
],
generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
"LeAudioSetConfigSchemas_h",
],
shared_libs: [
@@ -959,7 +946,6 @@ cc_test {
name: "bluetooth_le_audio_client_test",
test_suites: ["general-tests"],
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_bta_defaults",
"mts_defaults",
],
@@ -979,6 +965,7 @@ cc_test {
":TestMockMainShimEntry",
":TestMockStackBtmInterface",
":TestMockStackBtmIso",
+ ":TestMockStackGatt",
":TestMockStackL2cap",
":TestStubOsi",
"gatt/database.cc",
@@ -1111,6 +1098,7 @@ cc_test {
"le_audio/mock_codec_manager.cc",
],
shared_libs: [
+ "libaconfig_storage_read_api_cc",
"libbase",
"libcrypto",
"liblog",
@@ -1149,7 +1137,6 @@ cc_test {
test_suites: ["general-tests"],
defaults: [
"aconfig_lib_cc_shared_link.defaults",
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_bta_defaults",
"mts_defaults",
],
@@ -1181,6 +1168,7 @@ cc_test {
"le_audio/mock_codec_manager.cc",
],
shared_libs: [
+ "libaconfig_storage_read_api_cc",
"libbase",
"libbinder_ndk",
"libcrypto",
@@ -1262,6 +1250,7 @@ cc_test {
],
static_libs: [
"bluetooth_flags_c_lib_for_test",
+ "libaconfig_storage_read_api_cc",
"libbluetooth-types",
"libbluetooth_crypto_toolbox",
"libbluetooth_gd",
@@ -1346,9 +1335,6 @@ cc_test {
"libgmock",
"libosi",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
sanitize: {
cfi: true,
scs: true,
@@ -1417,9 +1403,6 @@ cc_test {
"libgmock",
"libosi",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
sanitize: {
cfi: true,
scs: true,
diff --git a/system/bta/BUILD.gn b/system/bta/BUILD.gn
index 928359ab22..425289338b 100644
--- a/system/bta/BUILD.gn
+++ b/system/bta/BUILD.gn
@@ -14,8 +14,7 @@
# limitations under the License.
#
-import("//bt/system/gd/dumpsys/bundler/bundler.gni")
-import("//common-mk/flatbuffer.gni")
+import("//bt/system/bta/bundler.gni")
static_library("bta") {
sources = [
diff --git a/system/bta/ag/bta_ag_act.cc b/system/bta/ag/bta_ag_act.cc
index 11a9de4c48..063cb4c18d 100644
--- a/system/bta/ag/bta_ag_act.cc
+++ b/system/bta/ag/bta_ag_act.cc
@@ -403,6 +403,7 @@ void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& /* data */) {
int i, num_active_conn = 0;
/* reinitialize stuff */
+ p_scb->clip[0] = 0;
p_scb->conn_service = 0;
p_scb->peer_features = 0;
p_scb->masked_features = p_scb->features;
diff --git a/system/bta/ag/bta_ag_int.h b/system/bta/ag/bta_ag_int.h
index ce9ff6298d..06caf10be9 100644
--- a/system/bta/ag/bta_ag_int.h
+++ b/system/bta/ag/bta_ag_int.h
@@ -161,9 +161,7 @@ typedef struct {
typedef struct {
tBTA_AG_RES result;
tBTA_AG_RES_DATA data;
- std::string ToString() const {
- return base::StringPrintf("result:%s", bta_ag_result_text(result).c_str());
- }
+ std::string ToString() const { return std::format("result:{}", bta_ag_result_text(result)); }
} tBTA_AG_API_RESULT;
/* data type for BTA_AG_API_SETCODEC_EVT */
@@ -240,6 +238,17 @@ typedef enum {
BTA_AG_SCO_APTX_SWB_SETTINGS_UNKNOWN = 0xFFFF,
} tBTA_AG_SCO_APTX_SWB_SETTINGS;
+namespace std {
+template <>
+struct formatter<tBTA_AG_SCO_MSBC_SETTINGS> : enum_formatter<tBTA_AG_SCO_MSBC_SETTINGS> {};
+template <>
+struct formatter<tBTA_AG_SCO_LC3_SETTINGS> : enum_formatter<tBTA_AG_SCO_LC3_SETTINGS> {};
+template <>
+struct formatter<tBTA_AG_SCO_APTX_SWB_SETTINGS> : enum_formatter<tBTA_AG_SCO_APTX_SWB_SETTINGS> {};
+template <>
+struct formatter<tBTA_AG_SCO> : enum_formatter<tBTA_AG_SCO> {};
+} // namespace std
+
/* state machine states */
typedef enum { BTA_AG_INIT_ST, BTA_AG_OPENING_ST, BTA_AG_OPEN_ST, BTA_AG_CLOSING_ST } tBTA_AG_STATE;
@@ -314,12 +323,11 @@ struct tBTA_AG_SCB {
HF indicators */
std::string ToString() const {
- return base::StringPrintf(
- "codec_updated=%d, codec_fallback=%d, nrec=%d"
- "sco_codec=%d, peer_codec=%d, msbc_settings=%d, lc3_settings=%d, "
- "device=%s",
+ return std::format(
+ "codec_updated={}, codec_fallback={}, nrec={}sco_codec={}, peer_codec={}, "
+ "msbc_settings={}, lc3_settings={}, device={}",
codec_updated, codec_fallback, nrec_enabled, sco_codec, peer_codecs,
- codec_msbc_settings, codec_lc3_settings, ADDRESS_TO_LOGGABLE_CSTR(peer_addr));
+ codec_msbc_settings, codec_lc3_settings, peer_addr);
}
};
@@ -476,11 +484,4 @@ bool bta_ag_is_sco_managed_by_audio();
*/
void bta_ag_stream_suspended();
-namespace std {
-template <>
-struct formatter<tBTA_AG_SCO_APTX_SWB_SETTINGS> : enum_formatter<tBTA_AG_SCO_APTX_SWB_SETTINGS> {};
-template <>
-struct formatter<tBTA_AG_SCO> : enum_formatter<tBTA_AG_SCO> {};
-} // namespace std
-
#endif /* BTA_AG_INT_H */
diff --git a/system/bta/ag/bta_ag_rfc.cc b/system/bta/ag/bta_ag_rfc.cc
index 1943492759..c96b867c71 100644
--- a/system/bta/ag/bta_ag_rfc.cc
+++ b/system/bta/ag/bta_ag_rfc.cc
@@ -215,11 +215,10 @@ static void bta_ag_port_cback_6(uint32_t code, uint16_t port_handle) {
static void bta_ag_setup_port(tBTA_AG_SCB* p_scb, uint16_t handle) {
int port_callback_index = bta_ag_scb_to_idx(p_scb) - 1;
log::assert_that(port_callback_index >= 0, "invalid callback index, handle={}, bd_addr={}",
- handle, ADDRESS_TO_LOGGABLE_STR(p_scb->peer_addr));
+ handle, p_scb->peer_addr);
log::assert_that(port_callback_index < static_cast<int>(sizeof(bta_ag_port_cback_tbl) /
sizeof(bta_ag_port_cback_tbl[0])),
- "callback index out of bound, handle={}, bd_addr={}", handle,
- ADDRESS_TO_LOGGABLE_STR(p_scb->peer_addr));
+ "callback index out of bound, handle={}, bd_addr={}", handle, p_scb->peer_addr);
if (PORT_SetEventMaskAndCallback(handle, BTA_AG_PORT_EV_MASK,
bta_ag_port_cback_tbl[port_callback_index]) != PORT_SUCCESS) {
log::warn("Unable to set RFCOMM event and callback mask peer:{} handle:{}", p_scb->peer_addr,
@@ -245,16 +244,16 @@ void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
int management_callback_index = bta_ag_scb_to_idx(p_scb) - 1;
log::assert_that(management_callback_index >= 0,
"invalid callback index, services=0x{:x}, bd_addr={}", services,
- ADDRESS_TO_LOGGABLE_STR(p_scb->peer_addr));
+ p_scb->peer_addr);
log::assert_that(
management_callback_index < static_cast<int>(sizeof(bta_ag_mgmt_cback_tbl) /
sizeof(bta_ag_mgmt_cback_tbl[0])),
"callback index out of bound, services=0x{:x}, bd_addr={}", services,
- ADDRESS_TO_LOGGABLE_STR(p_scb->peer_addr));
+ p_scb->peer_addr);
int status = RFCOMM_CreateConnectionWithSecurity(
bta_ag_uuid[i], bta_ag_cb.profile[i].scn, true, BTA_AG_MTU, RawAddress::kAny,
&(p_scb->serv_handle[i]), bta_ag_mgmt_cback_tbl[management_callback_index],
- BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, RfcommCfgInfo{});
if (status == PORT_SUCCESS) {
bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
} else {
@@ -331,7 +330,7 @@ void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
int status = RFCOMM_CreateConnectionWithSecurity(
bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU, p_scb->peer_addr,
&(p_scb->conn_handle), bta_ag_mgmt_cback_tbl[management_callback_index],
- BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, RfcommCfgInfo{});
log::verbose("p_scb=0x{}, conn_handle={}, mgmt_cback_index={}, status={}", std::format_ptr(p_scb),
p_scb->conn_handle, management_callback_index, status);
if (status == PORT_SUCCESS) {
diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index 7c4d8a04c1..8cb73a4402 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -26,7 +26,6 @@
#define LOG_TAG "bluetooth-a2dp"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -65,6 +64,7 @@
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/list.h"
+#include "osi/include/osi.h" // UINT_TO_PTR PTR_TO_UINT
#include "osi/include/properties.h"
#include "sdpdefs.h"
#include "stack/include/a2dp_ext.h"
@@ -114,6 +114,13 @@ constexpr char kBtmLogTag[] = "A2DP";
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
+/* Time to wait for open from SNK when signaling is initiated from SNK. */
+/* If not, we abort and try to initiate the connection as SRC. */
+#ifndef BTA_AV_ACCEPT_OPEN_TIMEOUT_MS
+#define BTA_AV_ACCEPT_OPEN_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#endif
+
+static void bta_av_accept_open_timer_cback(void* data);
static void bta_av_offload_codec_builder(tBTA_AV_SCB* p_scb, tBT_A2DP_OFFLOAD* p_a2dp_offload);
/* state machine states */
@@ -866,6 +873,9 @@ void bta_av_cleanup(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* /* p_data */) {
alarm_cancel(p_scb->avrc_ct_timer);
alarm_cancel(p_scb->link_signalling_timer);
alarm_cancel(p_scb->accept_signalling_timer);
+ if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
+ alarm_cancel(p_scb->accept_open_timer);
+ }
/* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
vendor_get_interface()->send_command(
@@ -1009,7 +1019,9 @@ void bta_av_disconnect_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* /* p_data */) {
alarm_cancel(p_scb->link_signalling_timer);
alarm_cancel(p_scb->accept_signalling_timer);
alarm_cancel(p_scb->avrc_ct_timer);
-
+ if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
+ alarm_cancel(p_scb->accept_open_timer);
+ }
// conn_lcb is the index bitmask of all used LCBs, and since LCB and SCB use
// the same index, it should be safe to use SCB index here.
if ((bta_av_cb.conn_lcb & (1 << p_scb->hdi)) != 0) {
@@ -1105,61 +1117,25 @@ void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
p_scb->SetAvdtpVersion(AVDT_VERSION_1_3);
}
- if (com::android::bluetooth::flags::avdt_discover_seps_as_acceptor()) {
- if (btif_av_src_sink_coexist_enabled()) {
- if (local_sep == AVDT_TSEP_SRC) {
- /* Make sure UUID has been initialized... */
- /* if local sep is source, uuid_int should be source */
- p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE;
- } else {
- p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SINK;
- }
- } else if (p_scb->uuid_int == 0) {
- p_scb->uuid_int = p_scb->open_api.uuid;
- }
- bta_av_discover_req(p_scb, NULL);
- } else {
- p_scb->num_seps = 1;
- if (A2DP_GetCodecType(p_scb->cfg.codec_info) == A2DP_MEDIA_CT_SBC) {
- /* if SBC is used by the SNK as INT, discover req is not sent in
- * bta_av_config_ind.
- * call disc_res now */
- /* this is called in A2DP SRC path only, In case of SINK we don't need it
- */
- if (local_sep == AVDT_TSEP_SRC) {
- p_scb->p_cos->disc_res(p_scb->hndl, p_scb->PeerAddress(), p_scb->num_seps,
- p_scb->num_seps, 0, UUID_SERVCLASS_AUDIO_SOURCE);
- }
+ if (btif_av_src_sink_coexist_enabled()) {
+ if (local_sep == AVDT_TSEP_SRC) {
+ /* Make sure UUID has been initialized... */
+ /* if local sep is source, uuid_int should be source */
+ p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE;
} else {
- /* we do not know the peer device and it is using non-SBC codec
- * we need to know all the SEPs on SNK */
- if (p_scb->uuid_int == 0) {
- p_scb->uuid_int = p_scb->open_api.uuid;
- }
- bta_av_discover_req(p_scb, NULL);
- return;
+ p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SINK;
}
-
- /* only in case of local sep as SRC we need to look for other SEPs, In case
- * of SINK we don't */
- if (btif_av_src_sink_coexist_enabled()) {
- if (local_sep == AVDT_TSEP_SRC) {
- /* Make sure UUID has been initialized... */
- /* if local sep is source, uuid_int should be source */
- p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE;
- bta_av_next_getcap(p_scb, p_data);
- } else {
- p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SINK;
- }
- } else {
- if (local_sep == AVDT_TSEP_SRC) {
- /* Make sure UUID has been initialized... */
- if (p_scb->uuid_int == 0) {
- p_scb->uuid_int = p_scb->open_api.uuid;
- }
- bta_av_next_getcap(p_scb, p_data);
- }
+ } else if (p_scb->uuid_int == 0) {
+ p_scb->uuid_int = p_scb->open_api.uuid;
+ }
+ bta_av_discover_req(p_scb, NULL);
+ if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
+ // Set timer to initiate stream opening if peer doesn't
+ if (!p_scb->accept_open_timer) {
+ p_scb->accept_open_timer = alarm_new("accept_open_timer");
}
+ alarm_set_on_mloop(p_scb->accept_open_timer, BTA_AV_ACCEPT_OPEN_TIMEOUT_MS,
+ bta_av_accept_open_timer_cback, UINT_TO_PTR(p_scb->hdi));
}
}
}
@@ -1180,6 +1156,9 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
log::verbose("peer {} bta_handle: 0x{:x}", p_scb->PeerAddress(), p_scb->hndl);
+ if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
+ alarm_cancel(p_scb->accept_open_timer);
+ }
msg.hdr.layer_specific = p_scb->hndl;
msg.is_up = true;
msg.peer_addr = p_scb->PeerAddress();
@@ -1782,11 +1761,6 @@ void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
log::info("sep_idx={} avdt_handle={} bta_handle=0x{:x} err_code=0x{:x}", p_scb->sep_idx,
p_scb->avdt_handle, p_scb->hndl, err_code);
- if (!com::android::bluetooth::flags::avdtp_error_codes()) {
- bta_av_adjust_seps_idx(p_scb, avdt_handle);
- err_code = AVDT_ERR_UNSUP_CFG;
- }
-
// The error code might not be set when the configuration is rejected
// based on the current AVDTP state.
if (err_code == AVDT_SUCCESS) {
@@ -1795,13 +1769,25 @@ void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
AVDT_ConfigRsp(avdt_handle, p_scb->avdt_label, err_code, 0);
- tBTA_AV bta_av_data = {
- .reject =
- {
- .bd_addr = p_data->str_msg.bd_addr,
- .hndl = p_scb->hndl,
- },
- };
+ tBTA_AV bta_av_data;
+
+ if (com::android::bluetooth::flags::bta_av_setconfig_rej_type_confusion()) {
+ bta_av_data = {
+ .reject =
+ {
+ .bd_addr = p_scb->PeerAddress(),
+ .hndl = p_scb->hndl,
+ },
+ };
+ } else {
+ bta_av_data = {
+ .reject =
+ {
+ .bd_addr = p_data->str_msg.bd_addr,
+ .hndl = p_scb->hndl,
+ },
+ };
+ }
(*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, &bta_av_data);
}
@@ -2036,8 +2022,8 @@ void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
log::debug("Reconfig codec: {}", A2DP_CodecInfoString(p_rcfg->codec_info));
BTM_LogHistory(kBtmLogTag, p_scb->PeerAddress(), "Codec reconfig",
- base::StringPrintf("%s => %s", A2DP_CodecName(p_scb->cfg.codec_info),
- A2DP_CodecName(p_rcfg->codec_info)));
+ std::format("{} => {}", A2DP_CodecName(p_scb->cfg.codec_info),
+ A2DP_CodecName(p_rcfg->codec_info)));
p_cfg->num_protect = p_rcfg->num_protect;
memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
@@ -3011,8 +2997,14 @@ void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
/* API open will be handled at timeout if SNK did not start signalling. */
/* API open will be ignored if SNK starts signalling. */
} else {
- /* SNK did not start signalling, API was called N seconds timeout. */
+ /* SNK did not start signalling or failed to complete the AVDT configuration in time. */
+ /* API was called N seconds timeout. */
/* We need to switch to INIT state and start opening connection. */
+ if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
+ // Reset peer device
+ bta_av_cco_close(p_scb, p_data);
+ alarm_cancel(p_scb->avrc_ct_timer);
+ }
p_scb->coll_mask = 0;
bta_av_set_scb_sst_init(p_scb);
@@ -3381,3 +3373,33 @@ void bta_av_api_set_peer_sep(tBTA_AV_DATA* p_data) {
}
}
}
+
+/*******************************************************************************
+ *
+ * Function bta_av_accept_open_timer_cback
+ *
+ * Description Process the timeout when SRC is accepting connection
+ * and SNK did not open the stream.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_accept_open_timer_cback(void* data) {
+ uint32_t hdi = PTR_TO_UINT(data);
+ tBTA_AV_SCB* p_scb = NULL;
+ if (hdi < BTA_AV_NUM_STRS) {
+ p_scb = bta_av_cb.p_scb[hdi];
+ }
+ if (p_scb == nullptr) {
+ log::error("SCB not found for index {}", hdi);
+ return;
+ }
+
+ /* Abort the current connection */
+ AVDT_AbortReq(p_scb->avdt_handle);
+
+ /* Try connecting and opening as initiator with event: BTA_AV_API_OPEN_EVT */
+ tBTA_AV_API_OPEN* p_buf = (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+ memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+ bta_sys_sendmsg(p_buf);
+} \ No newline at end of file
diff --git a/system/bta/av/bta_av_act.cc b/system/bta/av/bta_av_act.cc
index 32bcf56a1a..d45d63fd77 100644
--- a/system/bta/av/bta_av_act.cc
+++ b/system/bta/av/bta_av_act.cc
@@ -26,6 +26,7 @@
#define LOG_TAG "bluetooth-a2dp"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <cstddef>
#include <cstdint>
@@ -1408,7 +1409,10 @@ void bta_av_disable(tBTA_AV_CB* p_cb, tBTA_AV_DATA* /* p_data */) {
p_cb->p_scb[xx]->link_signalling_timer = NULL;
alarm_free(p_cb->p_scb[xx]->accept_signalling_timer);
p_cb->p_scb[xx]->accept_signalling_timer = NULL;
-
+ if (com::android::bluetooth::flags::avdt_handle_signaling_on_peer_failure()) {
+ alarm_free(p_cb->p_scb[xx]->accept_open_timer);
+ p_cb->p_scb[xx]->accept_open_timer = NULL;
+ }
hdr.layer_specific = xx + 1;
bta_av_api_deregister((tBTA_AV_DATA*)&hdr);
disabling_in_progress = true;
diff --git a/system/bta/av/bta_av_int.h b/system/bta/av/bta_av_int.h
index c9c176c445..abd79be555 100644
--- a/system/bta/av/bta_av_int.h
+++ b/system/bta/av/bta_av_int.h
@@ -492,6 +492,7 @@ public:
alarm_t* avrc_ct_timer; /* delay timer for AVRC CT */
alarm_t* link_signalling_timer;
alarm_t* accept_signalling_timer; /* timer to monitor signalling when accepting */
+ alarm_t* accept_open_timer; /* timer to monitor AVDT open when accepting */
uint16_t l2c_cid; /* L2CAP channel ID */
uint16_t stream_mtu; /* MTU of stream */
uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
diff --git a/system/bta/av/bta_av_main.cc b/system/bta/av/bta_av_main.cc
index 45a4ffd251..c9276a6564 100644
--- a/system/bta/av/bta_av_main.cc
+++ b/system/bta/av/bta_av_main.cc
@@ -1472,7 +1472,8 @@ void bta_debug_av_dump(int fd) {
if (lcb.addr.IsEmpty()) {
continue;
}
- dprintf(fd, "\n Link control block: %zu peer: %s\n", i, ADDRESS_TO_LOGGABLE_CSTR(lcb.addr));
+ dprintf(fd, "\n Link control block: %zu peer: %s\n", i,
+ lcb.addr.ToRedactedStringForLogging().c_str());
dprintf(fd, " Connected stream handle mask: 0x%x\n", lcb.conn_msk);
dprintf(fd, " Index(+1) to LCB: %d\n", lcb.lidx);
}
@@ -1484,7 +1485,8 @@ void bta_debug_av_dump(int fd) {
if (p_scb->PeerAddress().IsEmpty()) {
continue;
}
- dprintf(fd, "\n BTA ID: %zu peer: %s\n", i, ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()));
+ dprintf(fd, "\n BTA ID: %zu peer: %s\n", i,
+ p_scb->PeerAddress().ToRedactedStringForLogging().c_str());
dprintf(fd, " SDP discovery started: %s\n", p_scb->sdp_discovery_started ? "true" : "false");
for (size_t j = 0; j < BTAV_A2DP_CODEC_INDEX_MAX; j++) {
const tBTA_AV_SEP& sep = p_scb->seps[j];
@@ -1497,11 +1499,13 @@ void bta_debug_av_dump(int fd) {
dprintf(fd, " Codec: %s\n", A2DP_CodecName(sep.codec_info));
}
dprintf(fd, " BTA info tag: %d\n", p_scb->q_tag);
- dprintf(fd, " API Open peer: %s\n", ADDRESS_TO_LOGGABLE_CSTR(p_scb->q_info.open.bd_addr));
+ dprintf(fd, " API Open peer: %s\n",
+ p_scb->q_info.open.bd_addr.ToRedactedStringForLogging().c_str());
dprintf(fd, " Use AVRCP: %s\n", p_scb->q_info.open.use_rc ? "true" : "false");
dprintf(fd, " Switch result: %d\n", p_scb->q_info.open.switch_res);
dprintf(fd, " Initiator UUID: 0x%x\n", p_scb->q_info.open.uuid);
- dprintf(fd, " Saved API Open peer: %s\n", ADDRESS_TO_LOGGABLE_CSTR(p_scb->open_api.bd_addr));
+ dprintf(fd, " Saved API Open peer: %s\n",
+ p_scb->open_api.bd_addr.ToRedactedStringForLogging().c_str());
dprintf(fd, " Use AVRCP: %s\n", p_scb->open_api.use_rc ? "true" : "false");
dprintf(fd, " Switch result: %d\n", p_scb->open_api.switch_res);
dprintf(fd, " Initiator UUID: 0x%x\n", p_scb->open_api.uuid);
@@ -1509,6 +1513,8 @@ void bta_debug_av_dump(int fd) {
alarm_is_scheduled(p_scb->link_signalling_timer) ? "Scheduled" : "Not scheduled");
dprintf(fd, " Accept signalling timer: %s\n",
alarm_is_scheduled(p_scb->accept_signalling_timer) ? "Scheduled" : "Not scheduled");
+ dprintf(fd, " Accept open timer: %s\n",
+ alarm_is_scheduled(p_scb->accept_open_timer) ? "Scheduled" : "Not scheduled");
// TODO: Print p_scb->sep_info[], cfg, avrc_ct_timer, current_codec ?
dprintf(fd, " L2CAP Channel ID: %d\n", p_scb->l2c_cid);
dprintf(fd, " Stream MTU: %d\n", p_scb->stream_mtu);
diff --git a/system/gd/dumpsys/bundler/bundler.gni b/system/bta/bundler.gni
index 2942bbee1d..2942bbee1d 100644
--- a/system/gd/dumpsys/bundler/bundler.gni
+++ b/system/bta/bundler.gni
diff --git a/system/bta/csis/csis_client.cc b/system/bta/csis/csis_client.cc
index d38a232111..aba46a68c6 100644
--- a/system/bta/csis/csis_client.cc
+++ b/system/bta/csis/csis_client.cc
@@ -752,14 +752,15 @@ public:
for (auto& device : devices_) {
if (!g->IsDeviceInTheGroup(device)) {
if (device->GetExpectedGroupIdMember() == g->GetGroupId()) {
- stream << " == candidate addr: " << ADDRESS_TO_LOGGABLE_STR(device->addr)
+ stream << " == candidate addr: " << device->addr.ToRedactedStringForLogging()
<< "\n";
}
continue;
}
- stream << " == addr: " << ADDRESS_TO_LOGGABLE_STR(device->addr) << " ==\n"
- << " csis instance: data:" << "\n";
+ stream << " == addr: " << device->addr.ToRedactedStringForLogging() << " ==\n"
+ << " csis instance: data:"
+ << "\n";
auto instance = device->GetCsisInstanceByGroupId(g->GetGroupId());
if (!instance) {
diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc
index ec3ca882bc..7a931a6248 100644
--- a/system/bta/dm/bta_dm_act.cc
+++ b/system/bta/dm/bta_dm_act.cc
@@ -269,6 +269,13 @@ void BTA_dm_on_hw_on() {
}
}
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ /* Read low power processor offload features */
+ if (bta_dm_acl_cb.p_acl_cback) {
+ bta_dm_acl_cb.p_acl_cback(BTA_DM_LPP_OFFLOAD_FEATURES_READ, NULL);
+ }
+ }
+
btm_ble_scanner_init();
// Synchronize with the controller before continuing
@@ -1664,9 +1671,7 @@ static void bta_ble_energy_info_cmpl(tBTM_BLE_TX_TIME_MS tx_time, tBTM_BLE_RX_TI
tBTM_CONTRL_STATE ctrl_state = BTM_CONTRL_UNKNOWN;
if (BTA_SUCCESS == st) {
- ctrl_state = com::android::bluetooth::flags::bt_system_context_report()
- ? bta_dm_obtain_system_context()
- : bta_dm_pm_obtain_controller_state();
+ ctrl_state = bta_dm_obtain_system_context();
}
if (bta_dm_cb.p_energy_info_cback) {
diff --git a/system/bta/dm/bta_dm_device_search.cc b/system/bta/dm/bta_dm_device_search.cc
index 6f5691d050..b11200a074 100644
--- a/system/bta/dm/bta_dm_device_search.cc
+++ b/system/bta/dm/bta_dm_device_search.cc
@@ -19,7 +19,6 @@
#include "bta/dm/bta_dm_device_search.h"
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <stddef.h>
@@ -340,11 +339,10 @@ static void bta_dm_inq_cmpl() {
}
static void bta_dm_remote_name_cmpl(const tBTA_DM_REMOTE_NAME& remote_name_msg) {
- BTM_LogHistory(
- kBtmLogTag, remote_name_msg.bd_addr, "Remote name completed",
- base::StringPrintf("status:%s state:%s name:\"%s\"",
- hci_status_code_text(remote_name_msg.hci_status).c_str(),
- bta_dm_state_text(bta_dm_search_get_state()).c_str(),
+ BTM_LogHistory(kBtmLogTag, remote_name_msg.bd_addr, "Remote name completed",
+ std::format("status:{} state:{} name:\"{}\"",
+ hci_status_code_text(remote_name_msg.hci_status),
+ bta_dm_state_text(bta_dm_search_get_state()),
PRIVATE_NAME(reinterpret_cast<char const*>(remote_name_msg.bd_name))));
tBTM_INQ_INFO* p_btm_inq_info =
@@ -518,7 +516,7 @@ static void bta_dm_discover_name(const RawAddress& remote_bd_addr) {
(!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) {
if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, transport)) {
BTM_LogHistory(kBtmLogTag, bta_dm_search_cb.peer_bdaddr, "Read remote name",
- base::StringPrintf("Transport:%s", bt_transport_text(transport).c_str()));
+ std::format("Transport:{}", bt_transport_text(transport)));
return;
} else {
log::error("Unable to start read remote device name");
@@ -754,8 +752,7 @@ std::string EpochMillisToString(uint64_t time_ms) {
struct tm tm;
localtime_r(&time_sec, &tm);
std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm);
- return base::StringPrintf("%s.%03u", s.c_str(),
- static_cast<unsigned int>(time_ms % MillisPerSecond));
+ return std::format("{}.{:03}", s, time_ms % MillisPerSecond);
}
} // namespace
@@ -764,8 +761,7 @@ struct tSEARCH_STATE_HISTORY {
const tBTA_DM_DEVICE_SEARCH_STATE state;
const tBTA_DM_DEV_SEARCH_EVT event;
std::string ToString() const {
- return base::StringPrintf("state:%25s event:%s", bta_dm_state_text(state).c_str(),
- bta_dm_event_text(event).c_str());
+ return std::format("state:{:25s} event:{}", bta_dm_state_text(state), bta_dm_event_text(event));
}
};
diff --git a/system/bta/dm/bta_dm_device_search_int.h b/system/bta/dm/bta_dm_device_search_int.h
index 28e3fdabd8..35d41f1d2c 100644
--- a/system/bta/dm/bta_dm_device_search_int.h
+++ b/system/bta/dm/bta_dm_device_search_int.h
@@ -16,7 +16,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <string>
diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc
index f5d59d10de..2580e3a2da 100644
--- a/system/bta/dm/bta_dm_disc.cc
+++ b/system/bta/dm/bta_dm_disc.cc
@@ -19,7 +19,6 @@
#include "bta/dm/bta_dm_disc.h"
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -399,7 +398,7 @@ static void bta_dm_discover_services(tBTA_DM_API_DISCOVER& discover) {
}
BTM_LogHistory(kBtmLogTag, bd_addr, "Discovery started ",
- base::StringPrintf("Transport:%s", bt_transport_text(transport).c_str()));
+ std::format("Transport:{}", bt_transport_text(transport)));
if (transport == BT_TRANSPORT_LE) {
if (bta_dm_discovery_cb.transports & BT_TRANSPORT_LE) {
@@ -735,8 +734,7 @@ std::string EpochMillisToString(uint64_t time_ms) {
struct tm tm;
localtime_r(&time_sec, &tm);
std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm);
- return base::StringPrintf("%s.%03u", s.c_str(),
- static_cast<unsigned int>(time_ms % MillisPerSecond));
+ return std::format("{}.{:03}", s, time_ms % MillisPerSecond);
}
} // namespace
@@ -745,8 +743,7 @@ struct tDISCOVERY_STATE_HISTORY {
const tBTA_DM_SERVICE_DISCOVERY_STATE state;
const tBTA_DM_DISC_EVT event;
std::string ToString() const {
- return base::StringPrintf("state:%25s event:%s", bta_dm_state_text(state).c_str(),
- bta_dm_event_text(event).c_str());
+ return std::format("state:{:25s} event:{}", bta_dm_state_text(state), bta_dm_event_text(event));
}
};
diff --git a/system/bta/dm/bta_dm_disc_int.h b/system/bta/dm/bta_dm_disc_int.h
index 6c89f895fd..4714af997a 100644
--- a/system/bta/dm/bta_dm_disc_int.h
+++ b/system/bta/dm/bta_dm_disc_int.h
@@ -16,7 +16,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <queue>
diff --git a/system/bta/dm/bta_dm_disc_sdp.cc b/system/bta/dm/bta_dm_disc_sdp.cc
index 588e7afe96..dd467e210b 100644
--- a/system/bta/dm/bta_dm_disc_sdp.cc
+++ b/system/bta/dm/bta_dm_disc_sdp.cc
@@ -17,7 +17,6 @@
#define LOG_TAG "bt_bta_dm"
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -257,9 +256,9 @@ void bta_dm_sdp_result(tSDP_STATUS sdp_result, tBTA_DM_SDP_STATE* sdp_state) {
/* callbacks */
/* start next bd_addr if necessary */
BTM_LogHistory(kBtmLogTag, sdp_state->bd_addr, "Discovery completed",
- base::StringPrintf("Result:%s services_found:0x%x service_index:0x%d",
- sdp_result_text(sdp_result).c_str(),
- sdp_state->services_found, sdp_state->service_index));
+ std::format("Result:{} services_found:0x{:x} service_index:0x{}",
+ sdp_result_text(sdp_result), sdp_state->services_found,
+ sdp_state->service_index));
// Copy the raw_data to the discovery result structure
if (p_sdp_db != NULL && p_sdp_db->raw_used != 0 && p_sdp_db->raw_data != NULL) {
@@ -284,7 +283,7 @@ void bta_dm_sdp_result(tSDP_STATUS sdp_result, tBTA_DM_SDP_STATE* sdp_state) {
bta_dm_sdp_finished(sdp_state->bd_addr, result, uuid_list, gatt_uuids);
} else {
BTM_LogHistory(kBtmLogTag, sdp_state->bd_addr, "Discovery failed",
- base::StringPrintf("Result:%s", sdp_result_text(sdp_result).c_str()));
+ std::format("Result:{}", sdp_result_text(sdp_result)));
log::error("SDP connection failed {}", sdp_status_text(sdp_result));
/* not able to connect go to next device */
diff --git a/system/bta/dm/bta_dm_gatt_client.cc b/system/bta/dm/bta_dm_gatt_client.cc
index 3963f4b225..a78ed4ca33 100644
--- a/system/bta/dm/bta_dm_gatt_client.cc
+++ b/system/bta/dm/bta_dm_gatt_client.cc
@@ -18,7 +18,6 @@
#include <base/functional/bind.h>
#include <base/functional/callback.h>
-#include <base/strings/stringprintf.h>
#include <cstdint>
#include <string>
@@ -44,52 +43,47 @@ std::string EpochMillisToString(uint64_t time_ms) {
struct tm tm;
localtime_r(&time_sec, &tm);
std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm);
- return base::StringPrintf("%s.%03u", s.c_str(),
- static_cast<unsigned int>(time_ms % MillisPerSecond));
+ return std::format("{}.{:03}", s, time_ms % MillisPerSecond);
}
} // namespace
gatt_interface_t default_gatt_interface = {
.BTA_GATTC_CancelOpen =
[](tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct) {
- gatt_history_.Push(base::StringPrintf(
- "%-32s bd_addr:%s client_if:%hu is_direct:%c", "GATTC_CancelOpen",
- ADDRESS_TO_LOGGABLE_CSTR(remote_bda), static_cast<uint16_t>(client_if),
- (is_direct) ? 'T' : 'F'));
+ gatt_history_.Push(std::format("{:<32s} bd_addr:{} client_if:{} is_direct:{:c}",
+ "GATTC_CancelOpen", remote_bda, client_if,
+ is_direct ? 'T' : 'F'));
BTA_GATTC_CancelOpen(client_if, remote_bda, is_direct);
},
.BTA_GATTC_Refresh =
[](const RawAddress& remote_bda) {
- gatt_history_.Push(base::StringPrintf("%-32s bd_addr:%s", "GATTC_Refresh",
- ADDRESS_TO_LOGGABLE_CSTR(remote_bda)));
+ gatt_history_.Push(
+ std::format("{:<32s} bd_addr:{}", "GATTC_Refresh", remote_bda));
BTA_GATTC_Refresh(remote_bda);
},
.BTA_GATTC_GetGattDb =
[](tCONN_ID conn_id, uint16_t start_handle, uint16_t end_handle,
btgatt_db_element_t** db, int* count) {
- gatt_history_.Push(base::StringPrintf(
- "%-32s conn_id:%hu start_handle:%hu end:handle:%hu", "GATTC_GetGattDb",
- static_cast<uint16_t>(conn_id), start_handle, end_handle));
+ gatt_history_.Push(std::format("{:<32s} conn_id:{} start_handle:{} end:handle:{}",
+ "GATTC_GetGattDb", conn_id, start_handle,
+ end_handle));
BTA_GATTC_GetGattDb(conn_id, start_handle, end_handle, db, count);
},
.BTA_GATTC_AppRegister =
[](tBTA_GATTC_CBACK* p_client_cb, BtaAppRegisterCallback cb, bool eatt_support) {
- gatt_history_.Push(base::StringPrintf("%-32s eatt_support:%c",
- "GATTC_AppRegister",
- (eatt_support) ? 'T' : 'F'));
+ gatt_history_.Push(std::format("{:<32s} eatt_support:{:c}", "GATTC_AppRegister",
+ eatt_support ? 'T' : 'F'));
BTA_GATTC_AppRegister(p_client_cb, cb, eatt_support);
},
.BTA_GATTC_Close =
[](tCONN_ID conn_id) {
- gatt_history_.Push(base::StringPrintf("%-32s conn_id:%hu", "GATTC_Close",
- static_cast<uint16_t>(conn_id)));
+ gatt_history_.Push(std::format("{:<32s} conn_id:{}", "GATTC_Close", conn_id));
BTA_GATTC_Close(conn_id);
},
.BTA_GATTC_ServiceSearchRequest =
[](tCONN_ID conn_id, const bluetooth::Uuid* p_srvc_uuid) {
- gatt_history_.Push(base::StringPrintf("%-32s conn_id:%hu",
- "GATTC_ServiceSearchRequest",
- static_cast<uint16_t>(conn_id)));
+ gatt_history_.Push(
+ std::format("{:<32s} conn_id:{}", "GATTC_ServiceSearchRequest", conn_id));
if (p_srvc_uuid) {
BTA_GATTC_ServiceSearchRequest(conn_id, *p_srvc_uuid);
} else {
@@ -99,10 +93,10 @@ gatt_interface_t default_gatt_interface = {
.BTA_GATTC_Open =
[](tGATT_IF client_if, const RawAddress& remote_bda,
tBTM_BLE_CONN_TYPE connection_type, bool opportunistic, uint16_t preferred_mtu) {
- gatt_history_.Push(base::StringPrintf(
- "%-32s bd_addr:%s client_if:%hu type:0x%x opportunistic:%c", "GATTC_Open",
- ADDRESS_TO_LOGGABLE_CSTR(remote_bda), static_cast<uint16_t>(client_if),
- connection_type, (opportunistic) ? 'T' : 'F'));
+ gatt_history_.Push(std::format(
+ "{:<32s} bd_addr:{} client_if:{} type:0x{:x} opportunistic:{:c}",
+ "GATTC_Open", remote_bda, client_if, connection_type,
+ opportunistic ? 'T' : 'F'));
BTA_GATTC_Open(client_if, remote_bda, BLE_ADDR_PUBLIC, connection_type,
BT_TRANSPORT_LE, opportunistic, LE_PHY_1M, preferred_mtu);
},
diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h
index e79facd403..b5357bb06b 100644
--- a/system/bta/dm/bta_dm_int.h
+++ b/system/bta/dm/bta_dm_int.h
@@ -24,7 +24,6 @@
#ifndef BTA_DM_INT_H
#define BTA_DM_INT_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -79,7 +78,7 @@ inline std::string device_info_text(tBTA_DM_DEV_INFO info) {
":set_sniff", ":int_sniff", ":acp_sniff", ":unused", ":use_ssr", ":av_active",
};
- std::string s = base::StringPrintf("0x%02x", info);
+ std::string s = std::format("0x{:02x}", info);
if (info == BTA_DM_DI_NONE) {
return s + std::string(":none");
}
@@ -181,10 +180,8 @@ typedef struct {
bool new_request;
std::string ToString() const {
- return base::StringPrintf("peer:%s sys_name:%s app_id:%hhu state:%s new_request:%s",
- ADDRESS_TO_LOGGABLE_CSTR(peer_bdaddr), BtaIdSysText(id).c_str(),
- app_id, bta_sys_conn_status_text(state).c_str(),
- new_request ? "true" : "false");
+ return std::format("peer:{} sys_name:{} app_id:{} state:{} new_request:{}", peer_bdaddr,
+ BtaIdSysText(id), app_id, bta_sys_conn_status_text(state), new_request);
}
} tBTA_DM_SRVCS;
diff --git a/system/bta/dm/bta_dm_main.cc b/system/bta/dm/bta_dm_main.cc
index 966fb85d57..249c0d0431 100644
--- a/system/bta/dm/bta_dm_main.cc
+++ b/system/bta/dm/bta_dm_main.cc
@@ -21,7 +21,6 @@
* This is the main implementation file for the BTA device manager.
*
******************************************************************************/
-#include <base/strings/stringprintf.h>
#include <stddef.h>
#include "bta/dm/bta_dm_device_search.h"
diff --git a/system/bta/dm/bta_dm_sec_api.cc b/system/bta/dm/bta_dm_sec_api.cc
index f46bd40197..4d38a9680f 100644
--- a/system/bta/dm/bta_dm_sec_api.cc
+++ b/system/bta/dm/bta_dm_sec_api.cc
@@ -119,7 +119,12 @@ void BTA_DmAddDevice(RawAddress bd_addr, DEV_CLASS dev_class, LinkKey link_key,
/** This function removes a device from the security database list of peer
* device. It manages unpairing even while connected */
tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr) {
- bta_dm_remove_device(bd_addr);
+ if (!com::android::bluetooth::flags::remove_device_in_main_thread()) {
+ bta_dm_remove_device(bd_addr);
+ return BTA_SUCCESS;
+ }
+
+ do_in_main_thread(base::BindOnce(bta_dm_remove_device, bd_addr));
return BTA_SUCCESS;
}
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index 37ecf8f23c..9f5ad701c7 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -26,7 +26,6 @@
#define LOG_TAG "bt_bta_gattc"
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -49,7 +48,6 @@
// TODO(b/369381361) Enfore -Wmissing-prototypes
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-using base::StringPrintf;
using bluetooth::Uuid;
using namespace bluetooth;
@@ -766,9 +764,8 @@ void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data
log::verbose("Discovery cancel conn_id=0x{:x}", p_clcb->bta_conn_id);
if (p_clcb->disc_active ||
- (com::android::bluetooth::flags::gatt_rediscover_on_canceled() &&
- (p_clcb->request_during_discovery == BTA_GATTC_DISCOVER_REQ_READ_DB_HASH ||
- p_clcb->request_during_discovery == BTA_GATTC_DISCOVER_REQ_READ_DB_HASH_FOR_SVC_CHG))) {
+ (p_clcb->request_during_discovery == BTA_GATTC_DISCOVER_REQ_READ_DB_HASH ||
+ p_clcb->request_during_discovery == BTA_GATTC_DISCOVER_REQ_READ_DB_HASH_FOR_SVC_CHG)) {
bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_ERROR);
} else {
p_clcb->state = BTA_GATTC_CONN_ST;
diff --git a/system/bta/gatt/bta_gattc_cache.cc b/system/bta/gatt/bta_gattc_cache.cc
index 600cfa9edc..ce7deeeb9e 100644
--- a/system/bta/gatt/bta_gattc_cache.cc
+++ b/system/bta/gatt/bta_gattc_cache.cc
@@ -28,7 +28,6 @@
#include <base/functional/bind.h>
#include <base/functional/callback.h>
#include <base/strings/string_number_conversions.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -55,7 +54,6 @@
using namespace bluetooth::legacy::stack::sdp;
using namespace bluetooth;
-using base::StringPrintf;
using bluetooth::Uuid;
using gatt::Characteristic;
using gatt::Database;
diff --git a/system/bta/gatt/bta_gattc_int.h b/system/bta/gatt/bta_gattc_int.h
index 1bfd741348..4ceaff4062 100644
--- a/system/bta/gatt/bta_gattc_int.h
+++ b/system/bta/gatt/bta_gattc_int.h
@@ -505,7 +505,7 @@ inline std::string bta_clcb_state_text(const tBTA_GATTC_STATE& state) {
CASE_RETURN_TEXT(BTA_GATTC_CONN_ST);
CASE_RETURN_TEXT(BTA_GATTC_DISCOVER_ST);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", state);
+ return std::format("UNKNOWN[{}]", static_cast<int>(state));
}
}
@@ -517,7 +517,7 @@ inline std::string bta_server_state_text(const tBTA_GATTC_SERV_STATE& state) {
CASE_RETURN_TEXT(BTA_GATTC_SERV_DISC);
CASE_RETURN_TEXT(BTA_GATTC_SERV_DISC_ACT);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", state);
+ return std::format("UNKNOWN[{}]", static_cast<int>(state));
}
}
@@ -528,7 +528,7 @@ inline std::string bta_gattc_state_text(const tBTA_GATTC_CB_STATE& state) {
CASE_RETURN_TEXT(BTA_GATTC_STATE_ENABLED);
CASE_RETURN_TEXT(BTA_GATTC_STATE_DISABLING);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", state);
+ return std::format("UNKNOWN[{}]", static_cast<int>(state));
}
}
diff --git a/system/bta/gatt/bta_gattc_main.cc b/system/bta/gatt/bta_gattc_main.cc
index b4afcd542a..bf85b58697 100644
--- a/system/bta/gatt/bta_gattc_main.cc
+++ b/system/bta/gatt/bta_gattc_main.cc
@@ -23,14 +23,12 @@
******************************************************************************/
#define LOG_TAG "bta_gattc_main"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include "bta/gatt/bta_gattc_int.h"
#include "internal_include/bt_target.h"
#include "stack/include/bt_hdr.h"
-using base::StringPrintf;
using namespace bluetooth;
/*****************************************************************************
diff --git a/system/bta/gatt/bta_gattc_queue.cc b/system/bta/gatt/bta_gattc_queue.cc
index 40d99a7fb5..9afd9b3de7 100644
--- a/system/bta/gatt/bta_gattc_queue.cc
+++ b/system/bta/gatt/bta_gattc_queue.cc
@@ -145,51 +145,6 @@ void BtaGattQueue::gatt_read_multi_op_finished(tCONN_ID conn_id, tGATT_STATUS st
}
}
-void BtaGattQueue::gatt_read_multi_op_simulate(tCONN_ID conn_id, tGATT_STATUS status,
- uint16_t handle, uint16_t len, uint8_t* value,
- void* data_read) {
- gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)data_read;
-
- log::verbose("conn_id: 0x{:x} handle: 0x{:x} status: 0x{:x} len: {}", conn_id, handle, status,
- len);
- if (status == GATT_SUCCESS && ((data->values_end + 2 + len) < MAX_ATT_MTU)) {
- data->values[data->values_end] = (len & 0x00ff);
- data->values[data->values_end + 1] = (len & 0xff00) >> 8;
- data->values_end += 2;
-
- // concatenate all read values together
- std::copy(value, value + len, data->values.data() + data->values_end);
- data->values_end += len;
-
- if (data->read_index < data->handles.num_attr - 1) {
- // grab next handle and read it
- data->read_index++;
- uint16_t next_handle = data->handles.handles[data->read_index];
-
- BTA_GATTC_ReadCharacteristic(conn_id, next_handle, GATT_AUTH_REQ_NONE,
- gatt_read_multi_op_simulate, data_read);
- return;
- }
- }
-
- // all handles read, or bad status, or values too long
- GATT_READ_MULTI_OP_CB tmp_cb = data->cb;
- void* tmp_cb_data = data->cb_data;
-
- std::array<uint8_t, MAX_ATT_MTU> value_copy = data->values;
- uint16_t value_len = data->values_end;
- auto handles = data->handles;
-
- osi_free(data_read);
-
- mark_as_not_executing(conn_id);
- gatt_execute_next_op(conn_id);
-
- if (tmp_cb) {
- tmp_cb(conn_id, status, handles, value_len, value_copy.data(), tmp_cb_data);
- }
-}
-
void BtaGattQueue::gatt_execute_next_op(tCONN_ID conn_id) {
log::verbose("conn_id=0x{:x}", conn_id);
if (gatt_op_queue.empty()) {
@@ -255,28 +210,6 @@ void BtaGattQueue::gatt_execute_next_op(tCONN_ID conn_id) {
data->cb_data = op.read_cb_data;
BTA_GATTC_ReadMultiple(conn_id, op.handles, true, GATT_AUTH_REQ_NONE,
gatt_read_multi_op_finished, data);
- } else {
- /* This file contains just queue, and simulating reads should rather live in BTA or
- * stack/gatt. However, placing this logic in layers below would be significantly harder.
- * Having it here is a good balance - it's easy to add, and the API we expose to apps is same
- * as if it was in layers below.
- */
- log::verbose("EATT not supported, simulating read multi. conn_id: 0x{:x} num_handles: {}",
- conn_id, op.handles.num_attr);
- gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)osi_malloc(
- sizeof(gatt_read_multi_simulate_op_data));
- data->cb = op.read_multi_cb;
- data->cb_data = op.read_cb_data;
-
- std::fill(data->values.begin(), data->values.end(), 0);
- data->values_end = 0;
-
- data->handles = op.handles;
- data->read_index = 0;
- uint16_t handle = data->handles.handles[data->read_index];
-
- BTA_GATTC_ReadCharacteristic(conn_id, handle, GATT_AUTH_REQ_NONE, gatt_read_multi_op_simulate,
- data);
}
}
@@ -333,11 +266,15 @@ void BtaGattQueue::ConfigureMtu(tCONN_ID conn_id, uint16_t mtu) {
gatt_execute_next_op(conn_id);
}
-void BtaGattQueue::ReadMultiCharacteristic(tCONN_ID conn_id, tBTA_GATTC_MULTI& handles,
+bool BtaGattQueue::ReadMultiCharacteristic(tCONN_ID conn_id, tBTA_GATTC_MULTI& handles,
GATT_READ_MULTI_OP_CB cb, void* cb_data) {
+ if (!gatt_profile_get_eatt_support_by_conn_id(conn_id)) {
+ return false;
+ }
gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI,
.handles = handles,
.read_multi_cb = cb,
.read_cb_data = cb_data});
gatt_execute_next_op(conn_id);
+ return true;
}
diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc
index 36bbe69407..f1cbab7aee 100644
--- a/system/bta/gatt/bta_gattc_utils.cc
+++ b/system/bta/gatt/bta_gattc_utils.cc
@@ -920,7 +920,7 @@ void bta_gatt_client_dump(int fd) {
tBTA_GATTC_CONN* p_conn_track = &bta_gattc_cb.conn_track[i];
if (p_conn_track->in_use) {
entry_count++;
- stream << " address: " << ADDRESS_TO_LOGGABLE_STR(p_conn_track->remote_bda);
+ stream << " address: " << p_conn_track->remote_bda.ToRedactedStringForLogging();
stream << "\n";
}
}
@@ -934,7 +934,7 @@ void bta_gatt_client_dump(int fd) {
continue;
}
entry_count++;
- stream << " address: " << ADDRESS_TO_LOGGABLE_STR(p_bg_track->remote_bda)
+ stream << " address: " << p_bg_track->remote_bda.ToRedactedStringForLogging()
<< " cif_mask: " << loghex(p_bg_track->cif_mask);
stream << "\n";
}
@@ -974,7 +974,7 @@ void bta_gatt_client_dump(int fd) {
}
entry_count++;
stream << " conn_id: " << loghex(p_clcb->bta_conn_id)
- << " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda)
+ << " address: " << p_clcb->bda.ToRedactedStringForLogging()
<< " transport: " << bt_transport_text(p_clcb->transport)
<< " state: " << bta_clcb_state_text(p_clcb->state);
stream << "\n";
@@ -988,7 +988,7 @@ void bta_gatt_client_dump(int fd) {
}
entry_count++;
stream << " conn_id: " << loghex(p_clcb->bta_conn_id)
- << " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda)
+ << " address: " << p_clcb->bda.ToRedactedStringForLogging()
<< " transport: " << bt_transport_text(p_clcb->transport)
<< " state: " << bta_clcb_state_text(p_clcb->state);
stream << "\n";
@@ -1004,7 +1004,7 @@ void bta_gatt_client_dump(int fd) {
continue;
}
entry_count++;
- stream << " server_address: " << ADDRESS_TO_LOGGABLE_STR(p_known_server->server_bda)
+ stream << " server_address: " << p_known_server->server_bda.ToRedactedStringForLogging()
<< " mtu: " << p_known_server->mtu
<< " blocked_conn_id: " << loghex(p_known_server->blocked_conn_id)
<< " num_clcb: " << +p_known_server->num_clcb
diff --git a/system/bta/gatt/bta_gatts_act.cc b/system/bta/gatt/bta_gatts_act.cc
index c9c4427f51..b48b0cb5d1 100644
--- a/system/bta/gatt/bta_gatts_act.cc
+++ b/system/bta/gatt/bta_gatts_act.cc
@@ -415,15 +415,9 @@ void bta_gatts_open(tBTA_GATTS_CB* /* p_cb */, tBTA_GATTS_DATA* p_msg) {
p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if);
if (p_rcb != NULL) {
/* should always get the connection ID */
- bool success = false;
- if (com::android::bluetooth::flags::ble_gatt_server_use_address_type_in_connection()) {
- success = GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda,
- p_msg->api_open.remote_addr_type, p_msg->api_open.connection_type,
- p_msg->api_open.transport, false, LE_PHY_1M, 0);
- } else {
- success = GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda,
- p_msg->api_open.connection_type, p_msg->api_open.transport, false);
- }
+ bool success = GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda,
+ p_msg->api_open.remote_addr_type, p_msg->api_open.connection_type,
+ p_msg->api_open.transport, false, LE_PHY_1M, 0);
if (success) {
status = GATT_SUCCESS;
diff --git a/system/bta/groups/groups.cc b/system/bta/groups/groups.cc
index 42b271537a..2390a2793e 100644
--- a/system/bta/groups/groups.cc
+++ b/system/bta/groups/groups.cc
@@ -383,7 +383,7 @@ std::ostream& operator<<(std::ostream& out, bluetooth::groups::DeviceGroup const
<< " Uuid: " << group.group_uuid_ << std::endl;
out << " Devices:\n";
for (auto const& addr : group.devices_) {
- out << " " << ADDRESS_TO_LOGGABLE_STR(addr) << std::endl;
+ out << " " << addr.ToRedactedStringForLogging() << std::endl;
}
return out;
}
diff --git a/system/bta/has/has_client_test.cc b/system/bta/has/has_client_test.cc
index 322c387153..9c98258601 100644
--- a/system/bta/has/has_client_test.cc
+++ b/system/bta/has/has_client_test.cc
@@ -71,6 +71,7 @@ using ::bluetooth::le_audio::has::HasPreset;
using ::testing::_;
using ::testing::AnyNumber;
+using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::DoDefault;
using ::testing::Invoke;
@@ -1242,7 +1243,7 @@ TEST_F(HasClientTest, test_disconnect_connected_without_hap_connect_only_request
TestConnect(test_address);
EXPECT_CALL(*callbacks, OnConnectionState(ConnectionState::DISCONNECTED, test_address)).Times(1);
- EXPECT_CALL(gatt_queue, Clean(1)).Times(1);
+ EXPECT_CALL(gatt_queue, Clean(1)).Times(AtLeast(1));
TestDisconnect(test_address, 1);
}
@@ -1257,7 +1258,7 @@ TEST_F(HasClientTest, test_disconnect_connected) {
TestConnect(test_address);
EXPECT_CALL(*callbacks, OnConnectionState(ConnectionState::DISCONNECTED, test_address)).Times(1);
- EXPECT_CALL(gatt_queue, Clean(1)).Times(1);
+ EXPECT_CALL(gatt_queue, Clean(1)).Times(AtLeast(1));
TestDisconnect(test_address, 1);
}
@@ -1632,7 +1633,7 @@ TEST_F(HasClientTest, test_cp_not_usable_read_all_presets) {
OnDeviceAvailable(test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded |
bluetooth::has::kFeatureBitWritablePresets |
bluetooth::has::kFeatureBitDynamicPresets));
- EXPECT_CALL(gatt_queue, Clean(1)).Times(1);
+ EXPECT_CALL(gatt_queue, Clean(1)).Times(AtLeast(1));
TestConnect(test_address);
}
diff --git a/system/bta/has/has_ctp.cc b/system/bta/has/has_ctp.cc
index e9b45ca845..dbe41442d5 100644
--- a/system/bta/has/has_ctp.cc
+++ b/system/bta/has/has_ctp.cc
@@ -236,7 +236,7 @@ std::ostream& operator<<(std::ostream& out, const HasCtpOp& op) {
if (std::holds_alternative<int>(op.addr_or_group)) {
out << "\"group_id\": " << std::get<int>(op.addr_or_group);
} else if (std::holds_alternative<RawAddress>(op.addr_or_group)) {
- out << "\"address\": \"" << ADDRESS_TO_LOGGABLE_STR(std::get<RawAddress>(op.addr_or_group))
+ out << "\"address\": \"" << std::get<RawAddress>(op.addr_or_group).ToRedactedStringForLogging()
<< "\"";
} else {
out << "\"bad value\"";
diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc
index e27b420c8e..340e08d992 100644
--- a/system/bta/hearing_aid/hearing_aid.cc
+++ b/system/bta/hearing_aid/hearing_aid.cc
@@ -1070,9 +1070,7 @@ public:
/// The L2CAP will automatically reconnect the LE-ACL link on
/// disconnection when there is a pending channel request,
/// which invalidates all encryption checks performed here.
- com::android::bluetooth::flags::asha_encrypted_l2c_coc()
- ? BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT
- : BTM_SEC_NONE,
+ BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT,
HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
if (gap_handle == GAP_INVALID_HANDLE) {
@@ -1692,10 +1690,11 @@ public:
const struct AudioStats* stats = &device.audio_stats;
if (stats->rssi_history.size() <= 0) {
- dprintf(fd, " No RSSI history for %s:\n", ADDRESS_TO_LOGGABLE_CSTR(device.address));
+ dprintf(fd, " No RSSI history for %s:\n",
+ device.address.ToRedactedStringForLogging().c_str());
return;
}
- dprintf(fd, " RSSI history for %s:\n", ADDRESS_TO_LOGGABLE_CSTR(device.address));
+ dprintf(fd, " RSSI history for %s:\n", device.address.ToRedactedStringForLogging().c_str());
dprintf(fd, " Time of RSSI 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9\n");
for (auto& rssi_logs : stats->rssi_history) {
diff --git a/system/bta/hf_client/bta_hf_client_rfc.cc b/system/bta/hf_client/bta_hf_client_rfc.cc
index 42e8a3c96c..6e9655ac38 100644
--- a/system/bta/hf_client/bta_hf_client_rfc.cc
+++ b/system/bta/hf_client/bta_hf_client_rfc.cc
@@ -188,7 +188,7 @@ void bta_hf_client_start_server() {
port_status = RFCOMM_CreateConnectionWithSecurity(
UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb_arr.scn, true, BTA_HF_CLIENT_MTU,
RawAddress::kAny, &(bta_hf_client_cb_arr.serv_handle), bta_hf_client_mgmt_cback,
- BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, RfcommCfgInfo{});
log::verbose("started rfcomm server with handle {}", bta_hf_client_cb_arr.serv_handle);
@@ -240,10 +240,10 @@ void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) {
return;
}
- if (RFCOMM_CreateConnectionWithSecurity(UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn, false,
- BTA_HF_CLIENT_MTU, client_cb->peer_addr,
- &(client_cb->conn_handle), bta_hf_client_mgmt_cback,
- BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT) == PORT_SUCCESS) {
+ if (RFCOMM_CreateConnectionWithSecurity(
+ UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn, false, BTA_HF_CLIENT_MTU,
+ client_cb->peer_addr, &(client_cb->conn_handle), bta_hf_client_mgmt_cback,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, RfcommCfgInfo{}) == PORT_SUCCESS) {
bta_hf_client_setup_port(client_cb->conn_handle);
log::verbose("bta_hf_client_rfc_do_open : conn_handle = {}", client_cb->conn_handle);
} else {
diff --git a/system/bta/hf_client/bta_hf_client_sdp.cc b/system/bta/hf_client/bta_hf_client_sdp.cc
index 81721799f4..6e2585a6b8 100644
--- a/system/bta/hf_client/bta_hf_client_sdp.cc
+++ b/system/bta/hf_client/bta_hf_client_sdp.cc
@@ -25,6 +25,7 @@
******************************************************************************/
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <cstddef>
#include <cstdint>
@@ -351,6 +352,19 @@ void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) {
uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
}
+ /* If we already have a non-null discovery database at this point, we can get
+ * into a race condition leading to UAF once this connection is closed.
+ * This should only happen with malicious modifications to a client. */
+ if (com::android::bluetooth::flags::btsec_check_valid_discovery_database() &&
+ client_cb->p_disc_db != NULL) {
+ log::error("Tried to set up a HF client with a preexisting discovery database.");
+ client_cb->p_disc_db = NULL;
+ // We manually set the state here because it's possible to call this from an
+ // OPEN state, in which case the discovery fail event will be ignored.
+ client_cb->state = 0; // BTA_HF_CLIENT_INIT_ST
+ return;
+ }
+
/* allocate buffer for sdp database */
client_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
diff --git a/system/bta/hh/bta_hh_act.cc b/system/bta/hh/bta_hh_act.cc
index 116e572518..01a7e1652e 100644
--- a/system/bta/hh/bta_hh_act.cc
+++ b/system/bta/hh/bta_hh_act.cc
@@ -578,9 +578,8 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
conn.app_id = p_cb->app_id;
BTM_LogHistory(kBtmLogTag, p_cb->link_spec.addrt.bda, "Opened",
- base::StringPrintf("%s initiator:%s",
- bt_transport_text(p_cb->link_spec.transport).c_str(),
- (p_cb->incoming_conn) ? "remote" : "local"));
+ std::format("{} initiator:{}", bt_transport_text(p_cb->link_spec.transport),
+ (p_cb->incoming_conn) ? "remote" : "local"));
if (p_cb->link_spec.transport != BT_TRANSPORT_LE) {
/* inform role manager */
@@ -843,14 +842,12 @@ void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
disc_dat.handle = p_cb->hid_handle;
disc_dat.status = to_bta_hh_status(p_data->hid_cback.data);
- std::string overlay_fail = base::StringPrintf(
- "%s %s %s", (l2cap_conn_fail) ? "l2cap_conn_fail" : "",
- (l2cap_req_fail) ? "l2cap_req_fail" : "", (l2cap_cfg_fail) ? "l2cap_cfg_fail" : "");
- BTM_LogHistory(
- kBtmLogTag, p_cb->link_spec.addrt.bda, "Closed",
- base::StringPrintf("%s reason %s %s",
+ BTM_LogHistory(kBtmLogTag, p_cb->link_spec.addrt.bda, "Closed",
+ std::format("{} reason {} {} {} {}",
(p_cb->link_spec.transport == BT_TRANSPORT_LE) ? "le" : "classic",
- hid_status_text(hid_status).c_str(), overlay_fail.c_str()));
+ hid_status_text(hid_status), l2cap_conn_fail ? "l2cap_conn_fail" : "",
+ l2cap_req_fail ? "l2cap_req_fail" : "",
+ l2cap_cfg_fail ? "l2cap_cfg_fail" : ""));
/* inform role manager */
bta_sys_conn_close(BTA_ID_HH, p_cb->app_id, p_cb->link_spec.addrt.bda);
diff --git a/system/bta/hh/bta_hh_le.cc b/system/bta/hh/bta_hh_le.cc
index dab8a1d738..1f288716f7 100644
--- a/system/bta/hh/bta_hh_le.cc
+++ b/system/bta/hh/bta_hh_le.cc
@@ -1716,10 +1716,9 @@ static void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY* p_data) {
void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
const tBTA_HH_LE_CLOSE* le_close = &p_data->le_close;
- BTM_LogHistory(
- kBtmLogTag, p_cb->link_spec.addrt.bda, "Open failed",
- base::StringPrintf("%s reason %s", bt_transport_text(p_cb->link_spec.transport).c_str(),
- gatt_disconnection_reason_text(le_close->reason).c_str()));
+ BTM_LogHistory(kBtmLogTag, p_cb->link_spec.addrt.bda, "Open failed",
+ std::format("{} reason {}", bt_transport_text(p_cb->link_spec.transport),
+ gatt_disconnection_reason_text(le_close->reason)));
log::warn("Open failed for device:{}", p_cb->link_spec.addrt.bda);
/* open failure in the middle of service discovery, clear all services */
@@ -1763,10 +1762,9 @@ void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
const tBTA_HH_LE_CLOSE* le_close = &p_data->le_close;
- BTM_LogHistory(
- kBtmLogTag, p_cb->link_spec.addrt.bda, "Closed",
- base::StringPrintf("%s reason %s", bt_transport_text(p_cb->link_spec.transport).c_str(),
- gatt_disconnection_reason_text(le_close->reason).c_str()));
+ BTM_LogHistory(kBtmLogTag, p_cb->link_spec.addrt.bda, "Closed",
+ std::format("{} reason {}", bt_transport_text(p_cb->link_spec.transport),
+ gatt_disconnection_reason_text(le_close->reason)));
/* deregister all notification */
bta_hh_le_deregister_input_notif(p_cb);
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index 90f1508c50..60ab9b36a0 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -26,7 +26,6 @@
#define BTA_API_H
#include <base/functional/callback.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -124,7 +123,7 @@ inline std::string preferred_role_text(const tBTA_PREF_ROLES& role) {
CASE_RETURN_TEXT(BTA_CENTRAL_ROLE_ONLY);
CASE_RETURN_TEXT(BTA_PERIPHERAL_ROLE_ONLY);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", role);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(role));
}
}
@@ -157,10 +156,11 @@ typedef struct {
typedef uint8_t tBTA_DM_BLE_RSSI_ALERT_TYPE;
typedef enum : uint8_t {
- BTA_DM_LINK_UP_EVT = 5, /* Connection UP event */
- BTA_DM_LINK_DOWN_EVT = 6, /* Connection DOWN event */
- BTA_DM_LE_FEATURES_READ = 27, /* Controller specific LE features are read */
- BTA_DM_LINK_UP_FAILED_EVT = 34, /* Create connection failed event */
+ BTA_DM_LINK_UP_EVT = 5, /* Connection UP event */
+ BTA_DM_LINK_DOWN_EVT = 6, /* Connection DOWN event */
+ BTA_DM_LE_FEATURES_READ = 27, /* Controller specific LE features are read */
+ BTA_DM_LPP_OFFLOAD_FEATURES_READ = 28, /* Low power processor offload features are read */
+ BTA_DM_LINK_UP_FAILED_EVT = 34, /* Create connection failed event */
} tBTA_DM_ACL_EVT;
/* Structure associated with BTA_DM_LINK_UP_EVT */
@@ -216,7 +216,7 @@ inline std::string bta_dm_search_evt_text(const tBTA_DM_SEARCH_EVT& event) {
CASE_RETURN_TEXT(BTA_DM_NAME_READ_EVT);
CASE_RETURN_TEXT(BTA_DM_OBSERVE_CMPL_EVT);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", event);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(event));
}
}
diff --git a/system/bta/include/bta_api_data_types.h b/system/bta/include/bta_api_data_types.h
index 5b4cb3f27b..70b00d664c 100644
--- a/system/bta/include/bta_api_data_types.h
+++ b/system/bta/include/bta_api_data_types.h
@@ -18,7 +18,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -51,7 +50,7 @@ inline std::string bta_status_text(const tBTA_STATUS& status) {
CASE_RETURN_TEXT(BTA_NO_RESOURCES);
CASE_RETURN_TEXT(BTA_WRONG_MODE);
default:
- return base::StringPrintf("UNKNOWN[%d]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(status));
}
}
diff --git a/system/bta/include/bta_gatt_api.h b/system/bta/include/bta_gatt_api.h
index 8a8a91de9e..6e93821e4a 100644
--- a/system/bta/include/bta_gatt_api.h
+++ b/system/bta/include/bta_gatt_api.h
@@ -26,7 +26,6 @@
#define BTA_GATT_API_H
#include <base/functional/callback_forward.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <list>
@@ -95,7 +94,7 @@ inline std::string gatt_client_event_text(const tBTA_GATTC_EVT& event) {
CASE_RETURN_TEXT(BTA_GATTC_CONN_UPDATE_EVT);
CASE_RETURN_TEXT(BTA_GATTC_SUBRATE_CHG_EVT);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", event);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(event));
}
}
@@ -322,7 +321,7 @@ inline std::string gatt_server_event_text(const tBTA_GATTS_EVT& event) {
CASE_RETURN_TEXT(BTA_GATTS_CONN_UPDATE_EVT);
CASE_RETURN_TEXT(BTA_GATTS_SUBRATE_CHG_EVT);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", event);
+ return std::format("UNKNOWN[{}]", event);
}
}
diff --git a/system/bta/include/bta_gatt_queue.h b/system/bta/include/bta_gatt_queue.h
index 0f01f053cf..c530004f3d 100644
--- a/system/bta/include/bta_gatt_queue.h
+++ b/system/bta/include/bta_gatt_queue.h
@@ -44,11 +44,12 @@ public:
static void WriteDescriptor(tCONN_ID conn_id, uint16_t handle, std::vector<uint8_t> value,
tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb, void* cb_data);
static void ConfigureMtu(tCONN_ID conn_id, uint16_t mtu);
- /* This method uses "Read Multiple Variable Length Characteristic Values".
- * If EATT is not enabled on remote, it would send multiple regular Characteristic Reads, and
- * concatenate their values into Length Value Tuple List
+ /* This method queues "Read Multiple Variable Length Characteristic Values".
+ * Remote must support this method when it supports EATT.
+ * Returns true when remote supports EATT and operation was successfully queued.
+ * Returns false when remote doesn't support EATT and operation was not scheduled.
*/
- static void ReadMultiCharacteristic(tCONN_ID conn_id, tBTA_GATTC_MULTI& p_read_multi,
+ static bool ReadMultiCharacteristic(tCONN_ID conn_id, tBTA_GATTC_MULTI& p_read_multi,
GATT_READ_MULTI_OP_CB cb, void* cb_data);
/* Holds pending GATT operations */
@@ -80,8 +81,6 @@ private:
static void gatt_read_multi_op_finished(tCONN_ID conn_id, tGATT_STATUS status,
tBTA_GATTC_MULTI& handle, uint16_t len, uint8_t* value,
void* data);
- static void gatt_read_multi_op_simulate(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handle,
- uint16_t len, uint8_t* value, void* data_read);
// maps connection id to operations waiting for execution
static std::unordered_map<tCONN_ID, std::list<gatt_operation>> gatt_op_queue;
// contain connection ids that currently execute operations
diff --git a/system/bta/include/bta_hh_api.h b/system/bta/include/bta_hh_api.h
index 976c7d2bd8..b18bba5e60 100644
--- a/system/bta/include/bta_hh_api.h
+++ b/system/bta/include/bta_hh_api.h
@@ -18,7 +18,6 @@
#ifndef BTA_HH_API_H
#define BTA_HH_API_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -249,7 +248,7 @@ typedef struct {
uint8_t hid_handle;
std::string ToString() const {
- return base::StringPrintf("%04x::%04x::%04x", vendor_id, product_id, version);
+ return std::format("{:04x}::{:04x}::{:04x}", vendor_id, product_id, version);
}
} tBTA_HH_DEV_DSCP_INFO;
diff --git a/system/bta/include/bta_jv_api.h b/system/bta/include/bta_jv_api.h
index 4b43cbc485..8978ab00c2 100644
--- a/system/bta/include/bta_jv_api.h
+++ b/system/bta/include/bta_jv_api.h
@@ -33,6 +33,7 @@
#include "internal_include/bt_target.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/l2cap_types.h"
+#include "stack/include/port_api.h"
#include "stack/include/rfcdefs.h"
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
@@ -231,7 +232,7 @@ inline std::string bta_jv_event_text(const tBTA_JV_EVT& event) {
CASE_RETURN_TEXT(BTA_JV_RFCOMM_SRV_OPEN_EVT);
CASE_RETURN_TEXT(BTA_JV_MAX_EVT);
default:
- return base::StringPrintf("UNKNOWN[%hu]", event);
+ return std::format("UNKNOWN[{}]", static_cast<uint16_t>(event));
}
}
@@ -260,6 +261,11 @@ typedef struct {
int32_t tx_mtu; /* The transmit MTU */
uint16_t local_cid; /* The local CID */
uint16_t remote_cid; /* The remote CID */
+ uint16_t local_coc_mps; /* The local COC MPS */
+ uint16_t remote_coc_mps; /* The remote COC MPS */
+ uint16_t local_coc_credit; /* The local COC credit */
+ uint16_t remote_coc_credit; /* The remote COC credit */
+ uint16_t acl_handle; /* The ACL handle */
} tBTA_JV_L2CAP_OPEN;
/* data associated with BTA_JV_L2CAP_OPEN_EVT for LE sockets */
@@ -323,9 +329,19 @@ typedef struct {
/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
typedef struct {
- tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
- uint32_t handle; /* The connection handle */
- RawAddress rem_bda; /* The peer address */
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ RawAddress rem_bda; /* The peer address */
+ uint16_t rx_mtu; /* The receive (local) L2CAP MTU */
+ uint16_t tx_mtu; /* The transmit (remote) L2CAP MTU */
+ uint16_t local_credit; /* The local RFCOMM credit */
+ uint16_t remote_credit; /* The remote RFCOMM credit */
+ uint16_t local_cid; /* The local L2CAP CID */
+ uint16_t remote_cid; /* The remote L2CAP CID */
+ uint16_t dlci; /* DLCI */
+ uint16_t max_frame_size; /* The max frame size for RFCOMM */
+ uint16_t acl_handle; /* The ACL handle */
+ bool mux_initiator; /* Is the initiator of the RFCOMM multiplexer control channel */
} tBTA_JV_RFCOMM_OPEN;
/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */
typedef struct {
@@ -333,6 +349,16 @@ typedef struct {
uint32_t handle; /* The connection handle */
uint32_t new_listen_handle; /* The new listen handle */
RawAddress rem_bda; /* The peer address */
+ uint16_t rx_mtu; /* The receive (local) L2CAP MTU */
+ uint16_t tx_mtu; /* The transmit (remote) L2CAP MTU */
+ uint16_t local_credit; /* The local RFCOMM credit */
+ uint16_t remote_credit; /* The remote RFCOMM credit */
+ uint16_t local_cid; /* The local L2CAP CID */
+ uint16_t remote_cid; /* The remote L2CAP CID */
+ uint16_t dlci; /* DLCI */
+ uint16_t max_frame_size; /* The max frame size for RFCOMM */
+ uint16_t acl_handle; /* The ACL handle */
+ bool mux_initiator; /* Is the initiator of the RFCOMM multiplexer control channel */
} tBTA_JV_RFCOMM_SRV_OPEN;
/* data associated with BTA_JV_RFCOMM_CLOSE_EVT */
@@ -672,7 +698,7 @@ tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id, BT_HDR* msg, u
******************************************************************************/
tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, uint8_t remote_scn,
const RawAddress& peer_bd_addr, tBTA_JV_RFCOMM_CBACK* p_cback,
- uint32_t rfcomm_slot_id);
+ uint32_t rfcomm_slot_id, RfcommCfgInfo cfg);
/*******************************************************************************
*
@@ -702,7 +728,8 @@ tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, uint32_t rfcomm_slot_id);
*
******************************************************************************/
tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t max_session,
- tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id);
+ tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id,
+ RfcommCfgInfo cfg);
/*******************************************************************************
*
diff --git a/system/bta/include/bta_ras_api.h b/system/bta/include/bta_ras_api.h
index 8757c1382c..ee6eccec4f 100644
--- a/system/bta/include/bta_ras_api.h
+++ b/system/bta/include/bta_ras_api.h
@@ -38,6 +38,7 @@ public:
const RawAddress& address,
const std::vector<VendorSpecificCharacteristic>& vendor_specific_reply) = 0;
virtual void OnRasServerConnected(const RawAddress& identity_address) = 0;
+ virtual void OnMtuChangedFromServer(const RawAddress& address, uint16_t mtu) = 0;
virtual void OnRasServerDisconnected(const RawAddress& identity_address) = 0;
};
@@ -67,6 +68,7 @@ public:
virtual void OnWriteVendorSpecificReplyComplete(const RawAddress& address, bool success) = 0;
virtual void OnRemoteData(const RawAddress& address, const std::vector<uint8_t>& data) = 0;
virtual void OnRemoteDataTimeout(const RawAddress& address) = 0;
+ virtual void OnMtuChangedFromClient(const RawAddress& address, uint16_t mtu) = 0;
};
class RasClient {
diff --git a/system/bta/include/bta_sdp_api.h b/system/bta/include/bta_sdp_api.h
index 5eaf66bfb8..6a7c7832c8 100644
--- a/system/bta/include/bta_sdp_api.h
+++ b/system/bta/include/bta_sdp_api.h
@@ -24,8 +24,6 @@
#ifndef BTA_SDP_API_H
#define BTA_SDP_API_H
-#include <base/strings/stringprintf.h>
-
#include <cstdint>
#include <string>
@@ -50,7 +48,7 @@ inline std::string bta_sdp_status_text(const tBTA_SDP_STATUS& status) {
CASE_RETURN_TEXT(BTA_SDP_FAILURE);
CASE_RETURN_TEXT(BTA_SDP_BUSY);
default:
- return base::StringPrintf("UNKNOWN[%d]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(status));
}
}
diff --git a/system/bta/include/bta_sec_api.h b/system/bta/include/bta_sec_api.h
index a0f431f754..82d3029c91 100644
--- a/system/bta/include/bta_sec_api.h
+++ b/system/bta/include/bta_sec_api.h
@@ -19,7 +19,6 @@
#pragma once
#include <base/functional/callback.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
diff --git a/system/bta/jv/bta_jv_act.cc b/system/bta/jv/bta_jv_act.cc
index 9d4715269c..7b6fa38ca8 100644
--- a/system/bta/jv/bta_jv_act.cc
+++ b/system/bta/jv/bta_jv_act.cc
@@ -982,11 +982,31 @@ static void bta_jv_l2cap_client_cback(uint16_t gap_handle, uint16_t event, tGAP_
switch (event) {
case GAP_EVT_CONN_OPENED:
- evt_data.l2c_open.rem_bda = *GAP_ConnGetRemoteAddr(gap_handle);
- evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
- if (data != nullptr) {
- evt_data.l2c_open.local_cid = data->l2cap_cids.local_cid;
- evt_data.l2c_open.remote_cid = data->l2cap_cids.remote_cid;
+ if (!com::android::bluetooth::flags::socket_settings_api() ||
+ !GAP_IsTransportLe(gap_handle)) {
+ evt_data.l2c_open.rem_bda = *GAP_ConnGetRemoteAddr(gap_handle);
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ if (data != nullptr) {
+ evt_data.l2c_open.local_cid = data->l2cap_cids.local_cid;
+ evt_data.l2c_open.remote_cid = data->l2cap_cids.remote_cid;
+ }
+ } else {
+ uint16_t remote_mtu, local_mps, remote_mps, local_credit, remote_credit;
+ uint16_t local_cid, remote_cid, acl_handle;
+ evt_data.l2c_open.rem_bda = *GAP_ConnGetRemoteAddr(gap_handle);
+ if (GAP_GetLeChannelInfo(gap_handle, &remote_mtu, &local_mps, &remote_mps, &local_credit,
+ &remote_credit, &local_cid, &remote_cid,
+ &acl_handle) != PORT_SUCCESS) {
+ log::warn("Unable to get GAP channel info handle:{}", gap_handle);
+ }
+ evt_data.l2c_open.tx_mtu = remote_mtu;
+ evt_data.l2c_open.local_coc_mps = local_mps;
+ evt_data.l2c_open.remote_coc_mps = remote_mps;
+ evt_data.l2c_open.local_coc_credit = local_credit;
+ evt_data.l2c_open.remote_coc_credit = remote_credit;
+ evt_data.l2c_open.local_cid = local_cid;
+ evt_data.l2c_open.remote_cid = remote_cid;
+ evt_data.l2c_open.acl_handle = acl_handle;
}
p_cb->state = BTA_JV_ST_CL_OPEN;
p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->l2cap_socket_id);
@@ -1142,11 +1162,31 @@ static void bta_jv_l2cap_server_cback(uint16_t gap_handle, uint16_t event, tGAP_
switch (event) {
case GAP_EVT_CONN_OPENED:
- evt_data.l2c_open.rem_bda = *GAP_ConnGetRemoteAddr(gap_handle);
- evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
- if (data != nullptr) {
- evt_data.l2c_open.local_cid = data->l2cap_cids.local_cid;
- evt_data.l2c_open.remote_cid = data->l2cap_cids.remote_cid;
+ if (!com::android::bluetooth::flags::socket_settings_api() ||
+ !GAP_IsTransportLe(gap_handle)) {
+ evt_data.l2c_open.rem_bda = *GAP_ConnGetRemoteAddr(gap_handle);
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ if (data != nullptr) {
+ evt_data.l2c_open.local_cid = data->l2cap_cids.local_cid;
+ evt_data.l2c_open.remote_cid = data->l2cap_cids.remote_cid;
+ }
+ } else {
+ uint16_t remote_mtu, local_mps, remote_mps, local_credit, remote_credit;
+ uint16_t local_cid, remote_cid, acl_handle;
+ evt_data.l2c_open.rem_bda = *GAP_ConnGetRemoteAddr(gap_handle);
+ if (GAP_GetLeChannelInfo(gap_handle, &remote_mtu, &local_mps, &remote_mps, &local_credit,
+ &remote_credit, &local_cid, &remote_cid,
+ &acl_handle) != PORT_SUCCESS) {
+ log::warn("Unable to get GAP channel info handle:{}", gap_handle);
+ }
+ evt_data.l2c_open.tx_mtu = remote_mtu;
+ evt_data.l2c_open.local_coc_mps = local_mps;
+ evt_data.l2c_open.remote_coc_mps = remote_mps;
+ evt_data.l2c_open.local_coc_credit = local_credit;
+ evt_data.l2c_open.remote_coc_credit = remote_credit;
+ evt_data.l2c_open.local_cid = local_cid;
+ evt_data.l2c_open.remote_cid = remote_cid;
+ evt_data.l2c_open.acl_handle = acl_handle;
}
p_cb->state = BTA_JV_ST_SR_OPEN;
p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->l2cap_socket_id);
@@ -1401,6 +1441,16 @@ static void bta_jv_port_mgmt_cl_cback(const tPORT_RESULT code, uint16_t port_han
.rem_bda = rem_bda,
},
};
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (PORT_GetChannelInfo(port_handle, &evt_data.rfc_open.rx_mtu, &evt_data.rfc_open.tx_mtu,
+ &evt_data.rfc_open.local_credit, &evt_data.rfc_open.remote_credit,
+ &evt_data.rfc_open.local_cid, &evt_data.rfc_open.remote_cid,
+ &evt_data.rfc_open.dlci, &evt_data.rfc_open.max_frame_size,
+ &evt_data.rfc_open.acl_handle,
+ &evt_data.rfc_open.mux_initiator) != PORT_SUCCESS) {
+ log::warn("Unable to get RFCOMM channel info peer:{} handle:{}", rem_bda, port_handle);
+ }
+ }
p_pcb->state = BTA_JV_ST_CL_OPEN;
p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->rfcomm_slot_id);
} else {
@@ -1461,7 +1511,8 @@ static void bta_jv_port_event_cl_cback(uint32_t code, uint16_t port_handle) {
/* Client initiates an RFCOMM connection */
void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, uint8_t remote_scn, const RawAddress& peer_bd_addr,
- tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id) {
+ tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id,
+ RfcommCfgInfo cfg) {
uint16_t handle = 0;
uint32_t event_mask = BTA_JV_RFC_EV_MASK;
PortSettings port_settings;
@@ -1485,9 +1536,9 @@ void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, uint8_t remote_scn, const RawAddre
0);
}
- if (RFCOMM_CreateConnectionWithSecurity(UUID_SERVCLASS_SERIAL_PORT, remote_scn, false,
- BTA_JV_DEF_RFC_MTU, peer_bd_addr, &handle,
- bta_jv_port_mgmt_cl_cback, sec_mask) != PORT_SUCCESS) {
+ if (RFCOMM_CreateConnectionWithSecurity(
+ UUID_SERVCLASS_SERIAL_PORT, remote_scn, false, BTA_JV_DEF_RFC_MTU, peer_bd_addr,
+ &handle, bta_jv_port_mgmt_cl_cback, sec_mask, cfg) != PORT_SUCCESS) {
log::error("RFCOMM_CreateConnection failed");
bta_jv.rfc_cl_init.status = tBTA_JV_STATUS::FAILURE;
} else {
@@ -1608,6 +1659,17 @@ static void bta_jv_port_mgmt_sr_cback(const tPORT_RESULT code, uint16_t port_han
evt_data.rfc_srv_open.handle = p_pcb->handle;
evt_data.rfc_srv_open.status = tBTA_JV_STATUS::SUCCESS;
evt_data.rfc_srv_open.rem_bda = rem_bda;
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (PORT_GetChannelInfo(port_handle, &evt_data.rfc_srv_open.rx_mtu,
+ &evt_data.rfc_srv_open.tx_mtu, &evt_data.rfc_srv_open.local_credit,
+ &evt_data.rfc_srv_open.remote_credit,
+ &evt_data.rfc_srv_open.local_cid, &evt_data.rfc_srv_open.remote_cid,
+ &evt_data.rfc_srv_open.dlci, &evt_data.rfc_srv_open.max_frame_size,
+ &evt_data.rfc_srv_open.acl_handle,
+ &evt_data.rfc_srv_open.mux_initiator) != PORT_SUCCESS) {
+ log::warn("Unable to get RFCOMM channel info peer:{} handle:{}", rem_bda, port_handle);
+ }
+ }
tBTA_JV_PCB* p_pcb_new_listen = bta_jv_add_rfc_port(p_cb, p_pcb);
if (p_pcb_new_listen) {
evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle;
@@ -1735,9 +1797,10 @@ static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb
log::error("RFCOMM_CreateConnection failed: invalid port_handle");
}
- if (RFCOMM_CreateConnectionWithSecurity(
- p_cb->sec_id, p_cb->scn, true, BTA_JV_DEF_RFC_MTU, RawAddress::kAny,
- &(p_cb->rfc_hdl[si]), bta_jv_port_mgmt_sr_cback, sec_mask) == PORT_SUCCESS) {
+ if (RFCOMM_CreateConnectionWithSecurity(p_cb->sec_id, p_cb->scn, true, BTA_JV_DEF_RFC_MTU,
+ RawAddress::kAny, &(p_cb->rfc_hdl[si]),
+ bta_jv_port_mgmt_sr_cback, sec_mask,
+ RfcommCfgInfo{}) == PORT_SUCCESS) {
p_cb->curr_sess++;
p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1];
p_pcb->state = BTA_JV_ST_SR_LISTEN;
@@ -1781,7 +1844,8 @@ static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb
/* waits for an RFCOMM client to connect */
void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t max_session,
- tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id) {
+ tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id,
+ RfcommCfgInfo cfg) {
uint16_t handle = 0;
uint32_t event_mask = BTA_JV_RFC_EV_MASK;
PortSettings port_settings;
@@ -1795,7 +1859,7 @@ void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t ma
do {
if (RFCOMM_CreateConnectionWithSecurity(0, local_scn, true, BTA_JV_DEF_RFC_MTU,
RawAddress::kAny, &handle, bta_jv_port_mgmt_sr_cback,
- sec_mask) != PORT_SUCCESS) {
+ sec_mask, cfg) != PORT_SUCCESS) {
log::error("RFCOMM_CreateConnection failed");
break;
}
diff --git a/system/bta/jv/bta_jv_api.cc b/system/bta/jv/bta_jv_api.cc
index 1b5e715384..bf240a9834 100644
--- a/system/bta/jv/bta_jv_api.cc
+++ b/system/bta/jv/bta_jv_api.cc
@@ -415,7 +415,7 @@ tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id, BT_HDR* msg, u
******************************************************************************/
tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, uint8_t remote_scn,
const RawAddress& peer_bd_addr, tBTA_JV_RFCOMM_CBACK* p_cback,
- uint32_t rfcomm_slot_id) {
+ uint32_t rfcomm_slot_id, RfcommCfgInfo cfg) {
log::verbose("remote_scn:{}, peer_bd_addr:{}, rfcomm_slot_id:{}", remote_scn, peer_bd_addr,
rfcomm_slot_id);
@@ -424,7 +424,7 @@ tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, uint8_t remote_scn,
}
do_in_main_thread(Bind(&bta_jv_rfcomm_connect, sec_mask, remote_scn, peer_bd_addr, p_cback,
- rfcomm_slot_id));
+ rfcomm_slot_id, cfg));
return tBTA_JV_STATUS::SUCCESS;
}
@@ -469,7 +469,8 @@ tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, uint32_t rfcomm_slot_id) {
*
******************************************************************************/
tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t max_session,
- tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id) {
+ tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id,
+ RfcommCfgInfo cfg) {
log::verbose("local_scn:{}, rfcomm_slot_id:{}", local_scn, rfcomm_slot_id);
if (p_cback == NULL) {
@@ -485,7 +486,7 @@ tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, uint8_t local_scn, uin
}
do_in_main_thread(Bind(&bta_jv_rfcomm_start_server, sec_mask, local_scn, max_session, p_cback,
- rfcomm_slot_id));
+ rfcomm_slot_id, cfg));
return tBTA_JV_STATUS::SUCCESS;
}
diff --git a/system/bta/jv/bta_jv_int.h b/system/bta/jv/bta_jv_int.h
index f7aa7d106f..49ccd976b0 100644
--- a/system/bta/jv/bta_jv_int.h
+++ b/system/bta/jv/bta_jv_int.h
@@ -165,10 +165,12 @@ void bta_jv_l2cap_stop_server(uint16_t local_psm, uint32_t l2cap_socket_id);
void bta_jv_l2cap_write(uint32_t handle, uint32_t req_id, BT_HDR* msg, uint32_t user_id,
tBTA_JV_L2C_CB* p_cb);
void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, uint8_t remote_scn, const RawAddress& peer_bd_addr,
- tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id);
+ tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id,
+ RfcommCfgInfo cfg);
void bta_jv_rfcomm_close(uint32_t handle, uint32_t rfcomm_slot_id);
void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t max_session,
- tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id);
+ tBTA_JV_RFCOMM_CBACK* p_cback, uint32_t rfcomm_slot_id,
+ RfcommCfgInfo cfg);
void bta_jv_rfcomm_stop_server(uint32_t handle, uint32_t rfcomm_slot_id);
void bta_jv_rfcomm_write(uint32_t handle, uint32_t req_id, tBTA_JV_RFC_CB* p_cb,
tBTA_JV_PCB* p_pcb);
diff --git a/system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc b/system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc
index 58e2bb08c1..ee85db11e4 100644
--- a/system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc
+++ b/system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc
@@ -227,19 +227,12 @@ void SourceImpl::SendAudioData() {
sStats.media_read_last_underflow_us = bluetooth::common::time_get_os_boottime_us();
}
- if (com::android::bluetooth::flags::leaudio_hal_client_asrc()) {
- auto asrc_buffers = asrc_->Run(data);
-
- std::lock_guard<std::mutex> guard(audioSourceCallbacksMutex_);
- for (auto buffer : asrc_buffers) {
- if (audioSourceCallbacks_ != nullptr) {
- audioSourceCallbacks_->OnAudioDataReady(*buffer);
- }
- }
- } else {
- std::lock_guard<std::mutex> guard(audioSourceCallbacksMutex_);
+ auto asrc_buffers = asrc_->Run(data);
+
+ std::lock_guard<std::mutex> guard(audioSourceCallbacksMutex_);
+ for (auto buffer : asrc_buffers) {
if (audioSourceCallbacks_ != nullptr) {
- audioSourceCallbacks_->OnAudioDataReady(data);
+ audioSourceCallbacks_->OnAudioDataReady(*buffer);
}
}
}
@@ -267,11 +260,9 @@ bool SourceImpl::InitAudioSinkThread() {
void SourceImpl::StartAudioTicks() {
wakelock_acquire();
- if (com::android::bluetooth::flags::leaudio_hal_client_asrc()) {
- asrc_ = std::make_unique<bluetooth::audio::asrc::SourceAudioHalAsrc>(
- worker_thread_, source_codec_config_.num_channels, source_codec_config_.sample_rate,
- source_codec_config_.bits_per_sample, source_codec_config_.data_interval_us);
- }
+ asrc_ = std::make_unique<bluetooth::audio::asrc::SourceAudioHalAsrc>(
+ worker_thread_, source_codec_config_.num_channels, source_codec_config_.sample_rate,
+ source_codec_config_.bits_per_sample, source_codec_config_.data_interval_us);
audio_timer_.SchedulePeriodic(
worker_thread_->GetWeakPtr(), FROM_HERE,
base::BindRepeating(&SourceImpl::SendAudioData, weak_factory_.GetWeakPtr()),
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index 9c17be4088..0ce7da4f25 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -86,6 +86,7 @@
#include "osi/include/osi.h"
#include "osi/include/properties.h"
#include "stack/btm/btm_sec.h"
+#include "stack/gatt/gatt_int.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/btm_status.h"
@@ -234,6 +235,120 @@ LeAudioGroupStateMachine::Callbacks* stateMachineCallbacks;
DeviceGroupsCallbacks* device_group_callbacks;
LeAudioIsoDataCallback* iso_data_callback;
+class StreamSpeedTracker {
+public:
+ StreamSpeedTracker(void)
+ : is_started_(false),
+ group_id_(bluetooth::groups::kGroupUnknown),
+ num_of_devices_(0),
+ context_type_(LeAudioContextType::UNSPECIFIED),
+ reconfig_start_ts_(0),
+ setup_start_ts_(0),
+ total_time_(0),
+ reconfig_time_(0),
+ stream_setup_time_(0) {}
+
+ void Init(int group_id, LeAudioContextType context_type, int num_of_devices) {
+ Reset();
+ group_id_ = group_id;
+ context_type_ = context_type;
+ num_of_devices_ = num_of_devices;
+ log::verbose("StreamSpeedTracker group_id: {}, context: {} #{}", group_id_,
+ ToString(context_type_), num_of_devices);
+ }
+
+ void Reset(void) {
+ log::verbose("StreamSpeedTracker group_id: {}", group_id_);
+ is_started_ = false;
+ group_id_ = bluetooth::groups::kGroupUnknown;
+ reconfig_start_ts_ = setup_start_ts_ = total_time_ = reconfig_time_ = stream_setup_time_ =
+ num_of_devices_ = 0;
+ context_type_ = LeAudioContextType::UNSPECIFIED;
+ }
+
+ void ReconfigStarted(void) {
+ log::verbose("StreamSpeedTracker group_id: {}", group_id_);
+ reconfig_time_ = 0;
+ is_started_ = true;
+ reconfig_start_ts_ = bluetooth::common::time_get_os_boottime_us();
+ }
+
+ void StartStream(void) {
+ log::verbose("StreamSpeedTracker group_id: {}", group_id_);
+ setup_start_ts_ = bluetooth::common::time_get_os_boottime_us();
+ is_started_ = true;
+ }
+
+ void ReconfigurationComplete(void) {
+ reconfig_time_ = (bluetooth::common::time_get_os_boottime_us() - reconfig_start_ts_) / 1000;
+ log::verbose("StreamSpeedTracker group_id: {}, {} reconfig time {} ms", group_id_,
+ ToString(context_type_), reconfig_time_);
+ }
+
+ void StreamCreated(void) {
+ stream_setup_time_ = (bluetooth::common::time_get_os_boottime_us() - setup_start_ts_) / 1000;
+ log::verbose("StreamSpeedTracker group_id: {}, {} stream create time {} ms", group_id_,
+ ToString(context_type_), stream_setup_time_);
+ }
+
+ void StopStreamSetup(void) {
+ is_started_ = false;
+ uint64_t start_ts = reconfig_time_ != 0 ? reconfig_start_ts_ : setup_start_ts_;
+ total_time_ = (bluetooth::common::time_get_os_boottime_us() - start_ts) / 1000;
+ clock_gettime(CLOCK_REALTIME, &end_ts_);
+ log::verbose("StreamSpeedTracker group_id: {}, {} setup time {} ms", group_id_,
+ ToString(context_type_), total_time_);
+ }
+
+ bool IsStarted(void) {
+ if (is_started_) {
+ log::verbose("StreamSpeedTracker group_id: {}, {} is_started_: {} ", group_id_,
+ ToString(context_type_), is_started_);
+ } else {
+ log::verbose("StreamSpeedTracker not started ");
+ }
+ return is_started_;
+ }
+
+ void Dump(std::stringstream& stream) {
+ char ts[20];
+ std::strftime(ts, sizeof(ts), "%T", std::gmtime(&end_ts_.tv_sec));
+
+ if (total_time_ < 900) {
+ stream << "[ 🌟 ";
+ } else if (total_time_ < 1500) {
+ stream << "[ 🌤 ";
+ } else if (total_time_ < 2500) {
+ stream << "[ 🌧 ";
+ } else {
+ stream << "[ ❗ ";
+ }
+
+ stream << ts << ": Gid: " << group_id_ << "(#" << num_of_devices_ << "), " << context_type_
+ << ", ";
+ auto hal_idle = total_time_ - stream_setup_time_ - reconfig_time_;
+ if (reconfig_time_ != 0) {
+ stream << "t:" << total_time_ << "ms (r:" << reconfig_time_ << "/s:" << stream_setup_time_
+ << "/hal:" << hal_idle << ")";
+ } else {
+ stream << "t:" << total_time_ << "ms (hal:" << hal_idle << ")";
+ }
+ stream << "]";
+ }
+
+private:
+ bool is_started_;
+ int group_id_;
+ int num_of_devices_;
+ LeAudioContextType context_type_;
+ struct timespec end_ts_;
+ uint64_t reconfig_start_ts_;
+ uint64_t setup_start_ts_;
+ uint64_t total_time_;
+ uint64_t reconfig_time_;
+ uint64_t stream_setup_time_;
+};
+
/*
* Coordinatet Set Identification Profile (CSIP) based on CSIP 1.0
* and Coordinatet Set Identification Service (CSIS) 1.0
@@ -282,8 +397,6 @@ public:
configuration_context_type_(LeAudioContextType::UNINITIALIZED),
in_call_metadata_context_types_({.sink = AudioContexts(), .source = AudioContexts()}),
local_metadata_context_types_({.sink = AudioContexts(), .source = AudioContexts()}),
- stream_setup_start_timestamp_(0),
- stream_setup_end_timestamp_(0),
audio_receiver_state_(AudioState::IDLE),
audio_sender_state_(AudioState::IDLE),
in_call_(false),
@@ -505,6 +618,8 @@ public:
void AseInitialStateReadRequest(LeAudioDevice* leAudioDevice) {
int ases_num = leAudioDevice->ases_.size();
+ bool is_eatt_supported = gatt_profile_get_eatt_support_by_conn_id(leAudioDevice->conn_id_);
+
void* notify_flag_ptr = NULL;
tBTA_GATTC_MULTI multi_read{};
@@ -518,7 +633,7 @@ public:
notify_flag_ptr = INT_TO_PTR(leAudioDevice->notify_connected_after_read_);
}
- if (!com::android::bluetooth::flags::le_ase_read_multiple_variable()) {
+ if (!com::android::bluetooth::flags::le_ase_read_multiple_variable() || !is_eatt_supported) {
BtaGattQueue::ReadCharacteristic(leAudioDevice->conn_id_,
leAudioDevice->ases_[i].hdls.val_hdl, OnGattReadRspStatic,
notify_flag_ptr);
@@ -690,7 +805,8 @@ public:
leAudioDevice = group->GetNextActiveDevice(leAudioDevice);
} while (leAudioDevice);
- if (recovery) {
+ if (recovery && !group->NumOfConnected()) {
+ log::info("All devices disconnected, group becomes inactive");
/* Both devices will be disconnected soon. Notify upper layer that group
* is inactive */
groupSetAndNotifyInactive();
@@ -1031,7 +1147,7 @@ public:
return groupStateMachine_->ConfigureStream(group, configuration_context_type_,
remote_contexts, ccids);
} else if (!group_is_streaming) {
- stream_setup_start_timestamp_ = bluetooth::common::time_get_os_boottime_us();
+ speed_start_setup(group->group_id_, configuration_context_type, group->NumOfConnected());
}
/* If assistant have some connected delegators that needs to be informed
@@ -1176,7 +1292,7 @@ public:
pre_configuration_context_type_ = previous_context_type;
group->SetPendingConfiguration();
groupStateMachine_->StopStream(group);
- stream_setup_start_timestamp_ = bluetooth::common::time_get_os_boottime_us();
+ speed_start_setup(group->group_id_, configuration_context_type_, group->NumOfConnected(), true);
}
void SetInCall(bool in_call) override {
@@ -1896,11 +2012,26 @@ public:
dev->SetConnectionState(DeviceConnectState::DISCONNECTED);
}
}
+
+ /* If group is Streaming or is in transition for Streaming - lets stop it
+ * and mark device to disconnect when stream is closed
+ */
if (group->IsStreaming() || !group->IsReleasingOrIdle()) {
+ log::debug("group_id {} needs to stop streaming before {} disconnection",
+ group->group_id_, leAudioDevice->address_);
leAudioDevice->closing_stream_for_disconnection_ = true;
groupStateMachine_->StopStream(group);
return;
}
+
+ if (group->IsReleasing()) {
+ log::debug("group_id {} needs to stop streaming before {} disconnection",
+ group->group_id_, leAudioDevice->address_);
+ /* Stream is releasing, wait till it is completed and then disconnect ACL. */
+ leAudioDevice->closing_stream_for_disconnection_ = true;
+ return;
+ }
+
force_acl_disconnect &= group->IsEnabled();
}
@@ -2427,7 +2558,9 @@ public:
}
void ReadMustHaveAttributesOnReconnect(LeAudioDevice* leAudioDevice) {
- log::verbose("{}", leAudioDevice->address_);
+ bool is_eatt_supported = gatt_profile_get_eatt_support_by_conn_id(leAudioDevice->conn_id_);
+
+ log::verbose("{}, eatt supported {}", leAudioDevice->address_, is_eatt_supported);
/* Here we read
* 1) ASCS Control Point CCC descriptor in order to validate proper
* behavior of remote device which should store CCC values for bonded device.
@@ -2436,7 +2569,7 @@ public:
* it can change very often which, as we observed, might lead to not being sent by
* remote devices
*/
- if (!com::android::bluetooth::flags::le_ase_read_multiple_variable()) {
+ if (!com::android::bluetooth::flags::le_ase_read_multiple_variable() || !is_eatt_supported) {
BtaGattQueue::ReadCharacteristic(leAudioDevice->conn_id_,
leAudioDevice->audio_avail_hdls_.val_hdl,
OnGattReadRspStatic, NULL);
@@ -3396,7 +3529,7 @@ public:
group->group_id_);
scheduleAttachDeviceToTheStream(leAudioDevice->address_);
} else {
- stream_setup_start_timestamp_ = bluetooth::common::time_get_os_boottime_us();
+ speed_start_setup(group->group_id_, configuration_context_type_, 1);
}
}
@@ -4059,9 +4192,10 @@ public:
dprintf(fd, " Codec location: UNKNOWN\n");
}
- stream << " Start time: ";
- for (auto t : stream_start_history_queue_) {
- stream << static_cast<int>(t) << " ms, ";
+ stream << " Stream creation speed: ";
+ for (auto t : stream_speed_history_) {
+ t.Dump(stream);
+ stream << ",";
}
stream << "\n";
printCurrentStreamConfiguration(stream);
@@ -4268,10 +4402,21 @@ public:
return;
}
+ /* Group should not be resumed if:
+ * - configured context type is not allowed
+ * - updated metadata contains only not allowed context types
+ */
if (!group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSink)
+ .test_all(local_metadata_context_types_.source) ||
+ !group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSink)
.test(configuration_context_type_)) {
- log::warn("Block source resume request context type: {}",
- ToHexString(configuration_context_type_));
+ log::warn(
+ "Block source resume request context types: {}, allowed context mask: {}, "
+ "configured: {}",
+ ToString(local_metadata_context_types_.source),
+ ToString(group->GetAllowedContextMask(
+ bluetooth::le_audio::types::kLeAudioDirectionSink)),
+ ToString(configuration_context_type_));
CancelLocalAudioSourceStreamingRequest();
return;
}
@@ -4545,10 +4690,21 @@ public:
return;
}
+ /* Group should not be resumed if:
+ * - configured context type is not allowed
+ * - updated metadata contains only not allowed context types
+ */
if (!group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSource)
+ .test_all(local_metadata_context_types_.sink) ||
+ !group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSource)
.test(configuration_context_type_)) {
- log::warn("Block sink resume request context type: {}",
- ToHexString(configuration_context_type_));
+ log::warn(
+ "Block sink resume request context types: {} vs allowed context mask: {}, "
+ "configured: {}",
+ ToString(local_metadata_context_types_.sink),
+ ToString(group->GetAllowedContextMask(
+ bluetooth::le_audio::types::kLeAudioDirectionSource)),
+ ToString(configuration_context_type_));
CancelLocalAudioSourceStreamingRequest();
return;
}
@@ -4777,6 +4933,30 @@ public:
return true;
}
+ bool StopStreamIfUpdatedContextIsNoLongerSupporteded(uint8_t direction, LeAudioDeviceGroup* group,
+ AudioContexts local_contexts) {
+ AudioContexts allowed_contexts = group->GetAllowedContextMask(direction);
+
+ /* Stream should be suspended if:
+ * - updated metadata is only not allowed
+ * - there is no metadata (cleared) but configuration is for not allowed context
+ */
+ if (group->IsStreaming() && !allowed_contexts.test_any(local_contexts) &&
+ !(allowed_contexts.test(configuration_context_type_) && local_contexts.none())) {
+ /* SuspendForReconfiguration and ReconfigurationComplete is a workaround method to let Audio
+ * Framework know that session is suspended. Strem resume would be handled from
+ * suspended session context with stopped group.
+ */
+ SuspendedForReconfiguration();
+ ReconfigurationComplete(direction);
+ GroupStop(active_group_id_);
+
+ return true;
+ }
+
+ return false;
+ }
+
void OnLocalAudioSourceMetadataUpdate(
const std::vector<struct playback_track_metadata_v7>& source_metadata, DsaMode dsa_mode) {
if (active_group_id_ == bluetooth::groups::kGroupUnknown) {
@@ -4812,6 +4992,23 @@ public:
/* Set the remote sink metadata context from the playback tracks metadata */
local_metadata_context_types_.source = GetAudioContextsFromSourceMetadata(source_metadata);
+ /* Check if stream should be suspended due to reamaining only not allowed contexts in metadata
+ * or configured context.
+ */
+ if (com::android::bluetooth::flags::leaudio_stop_updated_to_not_available_context_stream() &&
+ StopStreamIfUpdatedContextIsNoLongerSupporteded(
+ bluetooth::le_audio::types::kLeAudioDirectionSink, group,
+ local_metadata_context_types_.source)) {
+ log::info(
+ "Updated source metadata contexts are not allowed context types: {} | configured: {} "
+ "vs allowed context mask: {}",
+ ToString(local_metadata_context_types_.source), ToString(configuration_context_type_),
+ ToString(group->GetAllowedContextMask(
+ bluetooth::le_audio::types::kLeAudioDirectionSink)));
+
+ return;
+ }
+
local_metadata_context_types_.source =
ChooseMetadataContextType(local_metadata_context_types_.source);
@@ -4962,6 +5159,22 @@ public:
/* Set remote source metadata context from the recording tracks metadata */
local_metadata_context_types_.sink = GetAudioContextsFromSinkMetadata(sink_metadata);
+ /* Check if stream should be suspended due to only reamaining not allowed contexts in metadata
+ * or configured context.
+ */
+ if (com::android::bluetooth::flags::leaudio_stop_updated_to_not_available_context_stream() &&
+ StopStreamIfUpdatedContextIsNoLongerSupporteded(
+ bluetooth::le_audio::types::kLeAudioDirectionSource, group,
+ local_metadata_context_types_.sink)) {
+ log::info(
+ "Updated sink metadata contexts are not allowed context types: {} | configured: {} "
+ "vs allowed context mask: {}",
+ ToString(local_metadata_context_types_.sink), ToString(configuration_context_type_),
+ ToString(group->GetAllowedContextMask(
+ bluetooth::le_audio::types::kLeAudioDirectionSource)));
+ return;
+ }
+
local_metadata_context_types_.sink =
ChooseMetadataContextType(local_metadata_context_types_.sink);
@@ -5589,21 +5802,50 @@ public:
}
}
- void take_stream_time(void) {
- if (stream_setup_start_timestamp_ == 0) {
+ void speed_start_setup(int group_id, LeAudioContextType context_type, int num_of_connected,
+ bool is_reconfig = false) {
+ log::verbose("is_started {} is_reconfig {} num_of_connected {}", speed_tracker_.IsStarted(),
+ is_reconfig, num_of_connected);
+ if (!speed_tracker_.IsStarted()) {
+ speed_tracker_.Init(group_id, context_type, num_of_connected);
+ }
+ if (is_reconfig) {
+ speed_tracker_.ReconfigStarted();
+ } else {
+ speed_tracker_.StartStream();
+ }
+ }
+
+ void speed_stop_reconfig(void) {
+ log::verbose("");
+ if (!speed_tracker_.IsStarted()) {
return;
}
+ speed_tracker_.ReconfigurationComplete();
+ }
- if (stream_start_history_queue_.size() == 10) {
- stream_start_history_queue_.pop_back();
+ void speed_stream_created() {
+ log::verbose("");
+ if (!speed_tracker_.IsStarted()) {
+ return;
}
- stream_setup_end_timestamp_ = bluetooth::common::time_get_os_boottime_us();
- stream_start_history_queue_.emplace_front(
- (stream_setup_end_timestamp_ - stream_setup_start_timestamp_) / 1000);
+ speed_tracker_.StreamCreated();
+ }
+
+ void speed_stop_setup() {
+ log::verbose("");
+ if (!speed_tracker_.IsStarted()) {
+ return;
+ }
- stream_setup_end_timestamp_ = 0;
- stream_setup_start_timestamp_ = 0;
+ if (stream_speed_history_.size() == 10) {
+ stream_speed_history_.pop_back();
+ }
+
+ speed_tracker_.StopStreamSetup();
+ stream_speed_history_.emplace_front(speed_tracker_);
+ speed_tracker_.Reset();
}
void notifyGroupStreamStatus(int group_id, GroupStreamStatus groupStreamStatus) {
@@ -5658,6 +5900,7 @@ public:
*/
CancelStreamingRequest();
ReconfigurationComplete(previously_active_directions);
+ speed_stop_reconfig();
}
void OnStateMachineStatusReportCb(int group_id, GroupStreamStatus status) {
@@ -5676,8 +5919,7 @@ public:
return;
}
- take_stream_time();
-
+ speed_stream_created();
bluetooth::le_audio::MetricsCollector::Get()->OnStreamStarted(active_group_id_,
configuration_context_type_);
@@ -5699,6 +5941,7 @@ public:
* Just stop streaming
*/
log::warn("Stopping stream for group {} as AF not interested.", group_id);
+ speed_stop_setup();
groupStateMachine_->StopStream(group);
return;
}
@@ -5713,6 +5956,7 @@ public:
"reconfigure to {}",
ToString(group->GetConfigurationContextType()),
ToString(configuration_context_type_));
+ speed_stop_setup();
initReconfiguration(group, group->GetConfigurationContextType());
return;
}
@@ -5733,11 +5977,12 @@ public:
if (audio_receiver_state_ == AudioState::READY_TO_START) {
StartReceivingAudio(group_id);
}
+
+ speed_stop_setup();
break;
}
case GroupStreamStatus::SUSPENDED:
- stream_setup_end_timestamp_ = 0;
- stream_setup_start_timestamp_ = 0;
+ speed_tracker_.Reset();
/** Stop Audio but don't release all the Audio resources */
SuspendAudio();
break;
@@ -5811,8 +6056,7 @@ public:
}
}
- stream_setup_end_timestamp_ = 0;
- stream_setup_start_timestamp_ = 0;
+ speed_tracker_.Reset();
CancelStreamingRequest();
if (group) {
@@ -5879,9 +6123,8 @@ private:
"persist.bluetooth.leaudio.allow.multiple.contexts";
BidirectionalPair<AudioContexts> in_call_metadata_context_types_;
BidirectionalPair<AudioContexts> local_metadata_context_types_;
- uint64_t stream_setup_start_timestamp_;
- uint64_t stream_setup_end_timestamp_;
- std::deque<uint64_t> stream_start_history_queue_;
+ StreamSpeedTracker speed_tracker_;
+ std::deque<StreamSpeedTracker> stream_speed_history_;
/* Microphone (s) */
AudioState audio_receiver_state_;
diff --git a/system/bta/le_audio/device_groups.cc b/system/bta/le_audio/device_groups.cc
index 192f3e9058..c3fd37b36d 100644
--- a/system/bta/le_audio/device_groups.cc
+++ b/system/bta/le_audio/device_groups.cc
@@ -1138,6 +1138,10 @@ bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const {
!in_transition_);
}
+bool LeAudioDeviceGroup::IsReleasing(void) const {
+ return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) && in_transition_;
+}
+
bool LeAudioDeviceGroup::IsGroupStreamReady(void) const {
bool is_device_ready = false;
@@ -2259,7 +2263,7 @@ void LeAudioDeviceGroup::Dump(std::stringstream& stream, int active_group_id) co
stream << "\n\t cis id: " << static_cast<int>(cis.id)
<< ",\ttype: " << static_cast<int>(cis.type)
<< ",\tconn_handle: " << static_cast<int>(cis.conn_handle)
- << ",\taddr: " << ADDRESS_TO_LOGGABLE_STR(cis.addr);
+ << ",\taddr: " << cis.addr.ToRedactedStringForLogging();
}
}
stream << "\n";
diff --git a/system/bta/le_audio/device_groups.h b/system/bta/le_audio/device_groups.h
index 40a87b0a71..f0fcb17125 100644
--- a/system/bta/le_audio/device_groups.h
+++ b/system/bta/le_audio/device_groups.h
@@ -112,6 +112,7 @@ public:
notify_streaming_when_cises_are_ready_(false),
audio_directions_(0),
dsa_({DsaMode::DISABLED, false}),
+ asymmetric_phy_for_unidirectional_cis_supported(true),
is_enabled_(true),
transport_latency_mtos_us_(0),
transport_latency_stom_us_(0),
@@ -142,8 +143,6 @@ public:
is_output_preference_le_audio = true;
is_duplex_preference_le_audio = true;
#endif
- asymmetric_phy_for_unidirectional_cis_supported =
- com::android::bluetooth::flags::asymmetric_phy_for_unidirectional_cis();
}
~LeAudioDeviceGroup(void);
@@ -407,6 +406,7 @@ public:
}
bool IsStreaming(void) const;
bool IsReleasingOrIdle(void) const;
+ bool IsReleasing(void) const;
void PrintDebugState(void) const;
void Dump(std::stringstream& stream, int active_group_id) const;
diff --git a/system/bta/le_audio/devices.cc b/system/bta/le_audio/devices.cc
index e30ecbd379..bb38daa805 100644
--- a/system/bta/le_audio/devices.cc
+++ b/system/bta/le_audio/devices.cc
@@ -1033,7 +1033,7 @@ void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream,
}
void LeAudioDevice::DumpPacsDebugState(std::stringstream& stream) {
- stream << " ● Device PACS, address: " << ADDRESS_TO_LOGGABLE_STR(address_) << "\n";
+ stream << " ● Device PACS, address: " << address_.ToRedactedStringForLogging() << "\n";
stream << "\t == Sink PACs:\n";
DumpPacsDebugState(stream, snk_pacs_);
stream << "\t == Source PACs:\n";
@@ -1060,7 +1060,7 @@ void LeAudioDevice::Dump(std::stringstream& stream) {
std::string snk_location = locationToString(snk_audio_locations_.to_ulong());
std::string src_location = locationToString(src_audio_locations_.to_ulong());
- stream << " ● Device address: " << ADDRESS_TO_LOGGABLE_STR(address_) << ", "
+ stream << " ● Device address: " << address_.ToRedactedStringForLogging() << ", "
<< connection_state_
<< ", conn_id: " << (conn_id_ == GATT_INVALID_CONN_ID ? "-1" : std::to_string(conn_id_))
<< ", acl_handle: " << std::to_string(acl_handle) << ", snk_location: " << snk_location
@@ -1387,9 +1387,14 @@ void LeAudioDevices::Cleanup(tGATT_IF client_if) {
continue;
}
- if (connection_state == DeviceConnectState::CONNECTING_AUTOCONNECT) {
- BTA_GATTC_CancelOpen(client_if, device->address_, false);
- } else {
+ // For connecting or connected device always remove background connect
+ BTA_GATTC_CancelOpen(client_if, device->address_, false);
+
+ if (connection_state == DeviceConnectState::CONNECTING_BY_USER) {
+ // When connecting by user, remove direct connect
+ BTA_GATTC_CancelOpen(client_if, device->address_, true);
+ } else if (connection_state != DeviceConnectState::CONNECTING_AUTOCONNECT) {
+ // If connected, close the connection
BtaGattQueue::Clean(device->conn_id_);
BTA_GATTC_Close(device->conn_id_);
device->DisconnectAcl();
diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc
index fe66085fa3..2891a9a8d4 100644
--- a/system/bta/le_audio/le_audio_client_test.cc
+++ b/system/bta/le_audio/le_audio_client_test.cc
@@ -492,6 +492,12 @@ protected:
base::Unretained(this->gatt_callback), event_data));
}
+ void TriggerDisconnectionFromApp(const RawAddress& address) {
+ do_in_main_thread(base::BindOnce(
+ [](LeAudioClient* client, const RawAddress& address) { client->Disconnect(address); },
+ LeAudioClient::Get(), address));
+ }
+
void InjectDisconnectedEvent(uint16_t conn_id,
tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST) {
ASSERT_NE(conn_id, GATT_INVALID_CONN_ID);
@@ -1434,9 +1440,15 @@ protected:
// Inject the state
group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
- group->SetState(group->GetTargetState());
+ group->SetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::RELEASING);
+ if (stay_at_releasing_stop_stream) {
+ log::info("StopStream {} -> stay in Releasing state", group->group_id_);
+ return;
+ }
+ group->SetState(group->GetTargetState());
+
do_in_main_thread(base::BindOnce(
[](bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* cb, int group_id) {
cb->StatusReportCb(group_id, GroupStreamStatus::IDLE);
@@ -1477,6 +1489,7 @@ protected:
SetUpMockCodecManager(codec_location);
stay_at_qos_config_in_start_stream = false;
+ stay_at_releasing_stop_stream = false;
available_snk_context_types_ = 0xffff;
available_src_context_types_ = 0xffff;
@@ -2699,6 +2712,7 @@ protected:
bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_;
std::map<int, LeAudioDeviceGroup*> streaming_groups;
bool stay_at_qos_config_in_start_stream = false;
+ bool stay_at_releasing_stop_stream = false;
bool attach_to_stream_scheduled = false;
@@ -2970,6 +2984,102 @@ TEST_F(UnicastTestNoInit, InitializeNoHal_2_1) {
"disable LE Audio Profile, or update your HAL");
}
+TEST_F(UnicastTest, CleanupWhenUserConnecting) {
+ const RawAddress test_address0 = GetTestAddress(0);
+ uint16_t conn_id = 1;
+ SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
+ codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
+ default_channel_cnt, 0x0004,
+ /* source sample freq 16khz */ true, /*add_csis*/
+ true, /*add_cas*/
+ true, /*add_pacs*/
+ default_ase_cnt /*add_ascs*/);
+
+ /* Remove default action on the direct connect */
+ ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)).WillByDefault(Return());
+ ConnectLeAudio(test_address0, false, false);
+
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)).Times(1);
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)).Times(1);
+ EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(conn_id, _)).Times(0);
+ EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(0);
+
+ LeAudioClient::Cleanup();
+ SyncOnMainLoop();
+
+ Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
+}
+
+TEST_F(UnicastTest, CleanupWhenAutoConnecting) {
+ const RawAddress test_address0 = GetTestAddress(0);
+ uint16_t conn_id = 1;
+ SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
+ codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
+ default_channel_cnt, 0x0004,
+ /* source sample freq 16khz */ true, /*add_csis*/
+ true, /*add_cas*/
+ true, /*add_pacs*/
+ default_ase_cnt /*add_ascs*/);
+
+ log::info("Connect device");
+ ConnectLeAudio(test_address0);
+
+ /* Remove default action on the autoconnect */
+ ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
+ .WillByDefault(Return());
+
+ EXPECT_CALL(mock_audio_hal_client_callbacks_,
+ OnConnectionState(ConnectionState::DISCONNECTED, test_address0))
+ .Times(1);
+ /* Make sure when remote device disconnects us, TA is used */
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _)).Times(1);
+ EXPECT_CALL(mock_gatt_interface_,
+ Open(gatt_if, test_address0, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
+ .Times(1);
+
+ InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER);
+ SyncOnMainLoop();
+
+ Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
+
+ log::info("Device is in auto connect");
+
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)).Times(1);
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)).Times(0);
+ EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(conn_id, _)).Times(0);
+ EXPECT_CALL(mock_gatt_interface_, Close(_)).Times(0);
+
+ LeAudioClient::Cleanup();
+ SyncOnMainLoop();
+
+ Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
+}
+
+TEST_F(UnicastTest, CleanupWhenConnected) {
+ const RawAddress test_address0 = GetTestAddress(0);
+ uint16_t conn_id = 1;
+ SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
+ codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
+ default_channel_cnt, 0x0004,
+ /* source sample freq 16khz */ true, /*add_csis*/
+ true, /*add_cas*/
+ true, /*add_pacs*/
+ default_ase_cnt /*add_ascs*/);
+
+ log::info("Connect device");
+ ConnectLeAudio(test_address0);
+
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false)).Times(1);
+ EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true)).Times(0);
+ EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(conn_id, _)).Times(1);
+ EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);
+
+ LeAudioClient::Cleanup();
+ SyncOnMainLoop();
+
+ Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
+}
+
TEST_F(UnicastTest, ConnectAndSetupPhy) {
const RawAddress test_address0 = GetTestAddress(0);
uint16_t conn_id = 1;
@@ -5960,6 +6070,63 @@ TEST_F(UnicastTest, DisconnecteWhileAlmostStreaming) {
ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
}
+TEST_F(UnicastTest, DisconnecteWhileAlmostStreaming_twoDevices) {
+ const RawAddress test_address0 = GetTestAddress(0);
+ const RawAddress test_address1 = GetTestAddress(1);
+ int group_id = 5;
+
+ TestSetupRemoteDevices(group_id);
+ SyncOnMainLoop();
+
+ EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1);
+
+ StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);
+
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
+ Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
+ Mock::VerifyAndClearExpectations(&mock_state_machine_);
+ SyncOnMainLoop();
+
+ ASSERT_NE(0lu, streaming_groups.count(group_id));
+ auto group_inject = streaming_groups.at(group_id);
+
+ // This shall be called once only when first device from the group is disconnecting.
+ EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1);
+
+ EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::DISCONNECTED, _))
+ .Times(0);
+
+ // Do not got to IDLE state imidiatelly.
+ stay_at_releasing_stop_stream = true;
+
+ log::info("First of all disconnect: {}", test_address0);
+ TriggerDisconnectionFromApp(test_address0);
+ SyncOnMainLoop();
+
+ log::info("Secondly disconnect: {}", test_address1);
+ TriggerDisconnectionFromApp(test_address1);
+ SyncOnMainLoop();
+
+ Mock::VerifyAndClearExpectations(&mock_state_machine_);
+ Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
+
+ EXPECT_CALL(mock_audio_hal_client_callbacks_,
+ OnConnectionState(ConnectionState::DISCONNECTED, test_address0))
+ .Times(1);
+ EXPECT_CALL(mock_audio_hal_client_callbacks_,
+ OnConnectionState(ConnectionState::DISCONNECTED, test_address1))
+ .Times(1);
+
+ do_in_main_thread(base::BindOnce(
+ [](bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* cb, int group_id) {
+ cb->StatusReportCb(group_id, GroupStreamStatus::IDLE);
+ },
+ state_machine_callbacks_, group_id));
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
+}
+
TEST_F(UnicastTest, EarbudsTwsStyleStreaming) {
const RawAddress test_address0 = GetTestAddress(0);
int group_id = bluetooth::groups::kGroupUnknown;
@@ -9856,6 +10023,71 @@ TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnectStreamStopTimeout) {
ASSERT_NE(device->GetConnectionState(), DeviceConnectState::DISCONNECTING_AND_RECOVER);
}
+TEST_F(UnicastTest, TwoEarbudsStreamingProfileDisconnectForSingleEarbudStreamStopTimeout) {
+ uint8_t group_size = 2;
+ int group_id = 2;
+
+ // Report working CSIS
+ ON_CALL(mock_csis_client_module_, IsCsisClientRunning()).WillByDefault(Return(true));
+
+ ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
+ .WillByDefault(Invoke([&](int /*group_id*/) { return group_size; }));
+
+ // First earbud
+ const RawAddress test_address0 = GetTestAddress(0);
+ ConnectCsisDevice(test_address0, 1 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontLeft,
+ codec_spec_conf::kLeAudioLocationFrontLeft, group_size, group_id, 1 /* rank*/);
+
+ // Second earbud
+ const RawAddress test_address1 = GetTestAddress(1);
+ ConnectCsisDevice(test_address1, 2 /*conn_id*/, codec_spec_conf::kLeAudioLocationFrontRight,
+ codec_spec_conf::kLeAudioLocationFrontRight, group_size, group_id, 2 /* rank*/,
+ true /*connect_through_csis*/);
+
+ // Audio sessions are started only when device gets active
+ EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1);
+ LeAudioClient::Get()->GroupSetActive(group_id);
+ SyncOnMainLoop();
+
+ /* Use StartStream to generate situation when target state is IDLE, one device is streaming and
+ * other one reached IDLE state.
+ */
+ ON_CALL(mock_state_machine_, StartStream(_, _, _, _))
+ .WillByDefault([this](LeAudioDeviceGroup* group,
+ types::LeAudioContextType /* context_type */,
+ types::BidirectionalPair<
+ types::AudioContexts> /* metadata_context_types */,
+ types::BidirectionalPair<std::vector<uint8_t>> /* ccid_lists */) {
+ group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
+ auto group_state = group->GetState();
+ LeAudioDevice* device = group->GetFirstDevice();
+ for (auto& ase : device->ases_) {
+ ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING;
+ ase.active = true;
+ }
+ device = group->GetNextDevice(device);
+ for (auto& ase : device->ases_) {
+ ase.state = types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE;
+ ase.active = false;
+ }
+
+ state_machine_callbacks_->OnStateTransitionTimeout(group->group_id_);
+
+ return true;
+ });
+
+ // Do not accept direct connect, but expect it to arrive.
+ ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, _)).WillByDefault(Return());
+
+ EXPECT_CALL(mock_btm_interface_, AclDisconnectFromHandle(_, _)).Times(1);
+ EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupStatus(group_id, GroupStatus::INACTIVE))
+ .Times(0);
+ StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, AUDIO_SOURCE_INVALID, false,
+ false);
+ SyncOnMainLoop();
+}
+
TEST_F(UnicastTest, EarbudsWithStereoSinkMonoSourceSupporting32kHz) {
const RawAddress test_address0 = GetTestAddress(0);
int group_id = 0;
@@ -12777,4 +13009,65 @@ TEST_F(UnicastTest, CodecFrameBlocks2) {
ASSERT_EQ(codec_manager_stream_params.sink.codec_frames_blocks_per_sdu, max_codec_frames_per_sdu);
}
+TEST_F(UnicastTestHandoverMode, UpdateMetadataToNotAllowedContexts) {
+ com::android::bluetooth::flags::provider_->leaudio_stop_updated_to_not_available_context_stream(
+ true);
+ const RawAddress test_address0 = GetTestAddress(0);
+ int group_id = bluetooth::groups::kGroupUnknown;
+
+ available_snk_context_types_ =
+ (types::LeAudioContextType::RINGTONE | types::LeAudioContextType::CONVERSATIONAL |
+ types::LeAudioContextType::UNSPECIFIED | types::LeAudioContextType::MEDIA |
+ types::LeAudioContextType::SOUNDEFFECTS)
+ .value();
+ available_src_context_types_ = available_snk_context_types_;
+ supported_snk_context_types_ = types::kLeAudioContextAllTypes.value();
+ supported_src_context_types_ =
+ (types::kLeAudioContextAllRemoteSource | types::LeAudioContextType::UNSPECIFIED).value();
+ /* Don't allow SOUNDEFFECTS context type to be streamed */
+ int allowed_context_types =
+ (types::LeAudioContextType::RINGTONE | types::LeAudioContextType::CONVERSATIONAL |
+ types::LeAudioContextType::UNSPECIFIED | types::LeAudioContextType::MEDIA)
+ .value();
+
+ SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
+ codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
+ default_channel_cnt, 0x0004, false /*add_csis*/, true /*add_cas*/,
+ true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/,
+ 0 /*rank*/);
+ EXPECT_CALL(mock_audio_hal_client_callbacks_,
+ OnConnectionState(ConnectionState::CONNECTED, test_address0))
+ .Times(1);
+ EXPECT_CALL(mock_audio_hal_client_callbacks_,
+ OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
+ .WillOnce(DoAll(SaveArg<1>(&group_id)));
+
+ ConnectLeAudio(test_address0);
+ ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);
+
+ EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1);
+ types::BidirectionalPair<types::AudioContexts> metadata = {.sink = types::AudioContexts(),
+ .source = types::AudioContexts()};
+ EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::MEDIA, _, _)).Times(1);
+
+ LeAudioClient::Get()->GroupSetActive(group_id);
+ SyncOnMainLoop();
+
+ /* Set the same allowed context mask for sink and source */
+ LeAudioClient::Get()->SetGroupAllowedContextMask(group_id, allowed_context_types,
+ allowed_context_types);
+
+ StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, AUDIO_SOURCE_INVALID,
+ false, false);
+
+ SyncOnMainLoop();
+ Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
+ Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
+
+ /* Expect stream to be stopped when not allowed context would be updated in metadata */
+ EXPECT_CALL(mock_state_machine_, StopStream(_));
+
+ UpdateLocalSourceMetadata(AUDIO_USAGE_ASSISTANCE_SONIFICATION, AUDIO_CONTENT_TYPE_UNKNOWN, true);
+}
+
} // namespace bluetooth::le_audio
diff --git a/system/bta/le_audio/le_audio_health_status.cc b/system/bta/le_audio/le_audio_health_status.cc
index 6b811e1174..b0729a6f9c 100644
--- a/system/bta/le_audio/le_audio_health_status.cc
+++ b/system/bta/le_audio/le_audio_health_status.cc
@@ -221,7 +221,8 @@ private:
void dumpsys_dev(int fd, const device_stats& dev) {
std::stringstream stream;
- stream << "\n " << ADDRESS_TO_LOGGABLE_STR(dev.address_) << ": " << dev.latest_recommendation_
+ stream << "\n " << dev.address_.ToRedactedStringForLogging() << ": "
+ << dev.latest_recommendation_
<< (dev.is_valid_service_ ? " service: OK" : " service : NOK")
<< (dev.is_valid_group_member_ ? " csis: OK" : " csis : NOK");
diff --git a/system/bta/le_audio/le_audio_log_history.cc b/system/bta/le_audio/le_audio_log_history.cc
index a53e4944ea..d6848f3f79 100644
--- a/system/bta/le_audio/le_audio_log_history.cc
+++ b/system/bta/le_audio/le_audio_log_history.cc
@@ -113,7 +113,7 @@ private:
history_->Push("%-*s GID %-3d %-*s: %-22s %s", kMaxLogHistoryTagLength,
tag.substr(0, kMaxLogHistoryTagLength).c_str(), group_id,
kMaxLogHistoryMsgLength, msg.substr(0, kMaxLogHistoryMsgLength).c_str(),
- ADDRESS_TO_LOGGABLE_CSTR(addr), extra.c_str());
+ addr.ToRedactedStringForLogging().c_str(), extra.c_str());
}
std::shared_ptr<TimestampedStringCircularBuffer> history_{nullptr};
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index cc59c4dad7..8a82e4a5e1 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -923,13 +923,21 @@ public:
}
uint8_t data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci;
+ bluetooth::le_audio::types::LeAudioCodecId codec = {
+ .coding_format = bluetooth::hci::kIsoCodingFormatTransparent,
+ .vendor_company_id = 0x0000,
+ .vendor_codec_id = 0x0000};
log::info("DSA mode used: {}", static_cast<int>(group->dsa_.mode));
switch (group->dsa_.mode) {
case DsaMode::ISO_HW:
data_path_id = bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault;
+ if (!com::android::bluetooth::flags::dsa_hw_transparent_codec()) {
+ codec = bluetooth::le_audio::types::kLeAudioCodecHeadtracking;
+ }
break;
case DsaMode::ISO_SW:
data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci;
+ codec = bluetooth::le_audio::types::kLeAudioCodecHeadtracking;
break;
default:
log::warn("Unexpected DsaMode: {}", static_cast<int>(group->dsa_.mode));
@@ -951,11 +959,9 @@ public:
bluetooth::hci::iso_manager::iso_data_path_params param = {
.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut,
.data_path_id = data_path_id,
- .codec_id_format = bluetooth::le_audio::types::kLeAudioCodecHeadtracking.coding_format,
- .codec_id_company =
- bluetooth::le_audio::types::kLeAudioCodecHeadtracking.vendor_company_id,
- .codec_id_vendor =
- bluetooth::le_audio::types::kLeAudioCodecHeadtracking.vendor_codec_id,
+ .codec_id_format = codec.coding_format,
+ .codec_id_company = codec.vendor_company_id,
+ .codec_id_vendor = codec.vendor_codec_id,
.controller_delay = 0x00000000,
.codec_conf = std::vector<uint8_t>(),
};
@@ -1070,8 +1076,7 @@ public:
log::assert_that(ase != nullptr,
"shouldn't be called without an active ASE, device {}, "
"group id: {}, cis handle 0x{:04x}",
- ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), event->cig_id,
- event->cis_conn_hdl);
+ leAudioDevice->address_, event->cig_id, event->cis_conn_hdl);
PrepareAndSendReceiverStartReady(leAudioDevice, ase);
}
@@ -1080,8 +1085,8 @@ public:
tGATT_WRITE_TYPE write_type = GATT_WRITE_NO_RSP;
if (value.size() > (leAudioDevice->mtu_ - 3)) {
- log::warn("{}, using long write procedure ({} > {})", leAudioDevice->address_,
- static_cast<int>(value.size()), leAudioDevice->mtu_ - 3);
+ log::warn("{}, using long write procedure ({} > {})", leAudioDevice->address_, value.size(),
+ leAudioDevice->mtu_ - 3);
/* Note, that this type is actually LONG WRITE.
* Meaning all the Prepare Writes plus Execute is handled in the stack
@@ -2151,7 +2156,8 @@ private:
/* Last node configured, process group to codec configured state */
group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
- if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
+ if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING ||
+ group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
if (group->cig.GetState() == CigState::CREATED) {
/* It can happen on the earbuds switch scenario. When one device
* is getting remove while other is adding to the stream and CIG is
diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc
index 7593bdeaf5..7fc2985b28 100644
--- a/system/bta/le_audio/state_machine_test.cc
+++ b/system/bta/le_audio/state_machine_test.cc
@@ -7370,6 +7370,68 @@ TEST_F(StateMachineTest, StartStreamAfterConfigureToQoS) {
testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
}
+TEST_F(StateMachineTest, StartStreamAfterConfigureToQoS_ConfigurationCaching) {
+ const auto context_type = kContextTypeMedia;
+ const auto leaudio_group_id = 6;
+ const auto num_devices = 2;
+
+ ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
+
+ // Prepare multiple fake connected devices in a group
+ auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
+ ASSERT_EQ(group->Size(), num_devices);
+
+ PrepareConfigureCodecHandler(group, 0, true);
+ PrepareConfigureQosHandler(group);
+ PrepareEnableHandler(group);
+ PrepareDisableHandler(group);
+ PrepareReleaseHandler(group);
+
+ InjectInitialConfiguredNotification(group);
+
+ auto* leAudioDevice = group->GetFirstDevice();
+ auto expected_devices_written = 0;
+ while (leAudioDevice) {
+ /* Three Writes:
+ * 1. Codec configure
+ * 2: Codec QoS
+ * 3: Enabling
+ */
+ EXPECT_CALL(gatt_queue,
+ WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, _,
+ GATT_WRITE_NO_RSP, _, _))
+ .Times(3);
+ expected_devices_written++;
+ leAudioDevice = group->GetNextDevice(leAudioDevice);
+ }
+ ASSERT_EQ(expected_devices_written, num_devices);
+
+ // Validate GroupStreamStatus
+ EXPECT_CALL(mock_callbacks_,
+ StatusReportCb(leaudio_group_id,
+ bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER));
+
+ // Start the configuration and stream Media content
+ LeAudioGroupStateMachine::Get()->ConfigureStream(group, context_type,
+ {.sink = types::AudioContexts(context_type),
+ .source = types::AudioContexts(context_type)},
+ {.sink = {}, .source = {}}, true);
+
+ testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+ ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
+
+ // Validate GroupStreamStatus
+ EXPECT_CALL(mock_callbacks_,
+ StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+ // Start the configuration and stream Media content
+ LeAudioGroupStateMachine::Get()->StartStream(group, context_type,
+ {.sink = types::AudioContexts(context_type),
+ .source = types::AudioContexts(context_type)});
+
+ testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+}
+
TEST_F(StateMachineTest, StopStreamAfterConfigureToQoS) {
const auto context_type = kContextTypeMedia;
const auto leaudio_group_id = 6;
diff --git a/system/bta/ras/ras_client.cc b/system/bta/ras/ras_client.cc
index 172645f00e..6dcf00c377 100644
--- a/system/bta/ras/ras_client.cc
+++ b/system/bta/ras/ras_client.cc
@@ -40,6 +40,7 @@
#include "stack/include/bt_types.h"
#include "stack/include/btm_ble_addr.h"
#include "stack/include/gap_api.h"
+#include "stack/include/l2cap_interface.h"
#include "stack/include/main_thread.h"
#include "types/ble_address_with_type.h"
#include "types/bluetooth/uuid.h"
@@ -68,6 +69,7 @@ class RasClientImpl : public bluetooth::ras::RasClient {
static constexpr uint16_t kFollowingSegmentTimeoutMs = 1000;
static constexpr uint16_t kRangingDataReadyTimeoutMs = 5000;
static constexpr uint16_t kInvalidConnInterval = 0; // valid value is from 0x0006 to 0x0C0
+ static constexpr uint16_t kMinimumRasMtu = 247; // 4.1 Maximum transmission unit of RAP 1.0
public:
struct GattReadCallbackData {
@@ -108,8 +110,13 @@ public:
RangingType ranging_type_ = RANGING_TYPE_NONE;
TimeoutType timeout_type_ = TIMEOUT_NONE;
uint16_t conn_interval_ = kInvalidConnInterval;
+ uint16_t mtu = kDefaultGattMtu;
const gatt::Characteristic* FindCharacteristicByUuid(Uuid uuid) {
+ if (service_ == nullptr) {
+ log::error("Can't find Ranging Service");
+ return nullptr;
+ }
for (auto& characteristic : service_->characteristics) {
if (characteristic.uuid == uuid) {
return &characteristic;
@@ -117,6 +124,7 @@ public:
}
return nullptr;
}
+
const gatt::Characteristic* FindCharacteristicByHandle(uint16_t handle) {
for (auto& characteristic : service_->characteristics) {
if (characteristic.value_handle == handle) {
@@ -230,6 +238,9 @@ public:
case BTA_GATTC_SEARCH_CMPL_EVT: {
OnGattServiceSearchComplete(p_data->search_cmpl);
} break;
+ case BTA_GATTC_CFG_MTU_EVT: {
+ OnGattConfigMtu(p_data->cfg_mtu);
+ } break;
case BTA_GATTC_NOTIF_EVT: {
OnGattNotification(p_data->notify);
} break;
@@ -247,9 +258,13 @@ public:
log::debug("no ongoing measurement, skip");
return;
}
- tracker->conn_interval_ = evt.interval;
- log::info("conn interval is updated as {}", evt.interval);
- callbacks_->OnConnIntervalUpdated(tracker->address_for_cs_, tracker->conn_interval_);
+ if (tracker->conn_interval_ != evt.interval) {
+ tracker->conn_interval_ = evt.interval;
+ log::info("conn interval is updated as {}", evt.interval);
+ callbacks_->OnConnIntervalUpdated(tracker->address_for_cs_, tracker->conn_interval_);
+ } else {
+ log::debug("conn interval was not updated");
+ }
}
void OnGattConnected(const tBTA_GATTC_OPEN& evt) {
@@ -275,6 +290,9 @@ public:
}
tracker->conn_id_ = evt.conn_id;
tracker->is_connected_ = true;
+ tracker->conn_interval_ =
+ bluetooth::stack::l2cap::get_interface().L2CA_GetBleConnInterval(tracker->address_);
+ log::debug("The initial conn interval {}", tracker->conn_interval_);
log::info("Search service");
BTA_GATTC_ServiceSearchRequest(tracker->conn_id_, kRangingService);
}
@@ -310,6 +328,9 @@ public:
break;
}
}
+ // config mtu anyway, if it had been configured by others, it can get the current mtu.
+ log::info("config the MTU size as RAP minimum value {}", kMinimumRasMtu);
+ BTA_GATTC_ConfigureMTU(evt.conn_id, kMinimumRasMtu);
if (tracker->service_search_complete_) {
log::info("Service search already completed, ignore");
@@ -362,6 +383,20 @@ public:
}
}
+ void OnGattConfigMtu(const tBTA_GATTC_CFG_MTU& evt) {
+ if (evt.status != GATT_SUCCESS) {
+ log::warn("Failed to config the MTU size:{}", evt.mtu);
+ return;
+ }
+ // the MTU is always 517 since android 14
+ log::info("conn_id=0x{:04x}, status:{}, mtu:{}", evt.conn_id, evt.status, evt.mtu);
+ auto tracker = FindTrackerByHandle(evt.conn_id);
+ if (tracker != nullptr) {
+ tracker->mtu = evt.mtu;
+ callbacks_->OnMtuChangedFromClient(tracker->address_for_cs_, evt.mtu);
+ }
+ }
+
bool UseCachedData(std::shared_ptr<RasTracker> tracker) {
auto cached_data = cached_data_.find(tracker->address_);
if (cached_data == cached_data_.end()) {
diff --git a/system/bta/ras/ras_server.cc b/system/bta/ras/ras_server.cc
index 006c1bce5d..9daf6e646e 100644
--- a/system/bta/ras/ras_server.cc
+++ b/system/bta/ras/ras_server.cc
@@ -85,6 +85,7 @@ public:
PendingWriteResponse pending_write_response_;
uint16_t last_ready_procedure_ = 0;
uint16_t last_overwritten_procedure_ = 0;
+ uint16_t mtu = kDefaultGattMtu;
};
void Initialize() override {
@@ -210,6 +211,9 @@ public:
case BTA_GATTS_DISCONNECT_EVT: {
OnGattDisconnect(p_data);
} break;
+ case BTA_GATTS_MTU_EVT: {
+ OnGattMtuChanged(p_data->req_data);
+ } break;
case BTA_GATTS_REG_EVT: {
OnGattServerRegister(p_data);
} break;
@@ -250,6 +254,19 @@ public:
callbacks_->OnRasServerConnected(identity_address);
}
+ void OnGattMtuChanged(const tBTA_GATTS_REQ& req_data) {
+ auto remote_bda = req_data.remote_bda;
+ log::info("mtu is changed as {}", req_data.p_data->mtu);
+ auto it = trackers_.find(remote_bda);
+ if (it != trackers_.end()) {
+ it->second.mtu = req_data.p_data->mtu;
+
+ tBLE_ADDR_TYPE address_type = BLE_ADDR_PUBLIC_ID;
+ btm_random_pseudo_to_identity_addr(&remote_bda, &address_type);
+ callbacks_->OnMtuChangedFromServer(remote_bda, it->second.mtu);
+ }
+ }
+
void OnGattDisconnect(tBTA_GATTS* p_data) {
auto remote_bda = p_data->conn.remote_bda;
log::info("Address: {}, conn_id:{}", remote_bda, p_data->conn.conn_id);
@@ -322,7 +339,7 @@ public:
btgatt_db_element_t ras_control_point;
ras_control_point.uuid = kRasControlPointCharacteristic;
ras_control_point.type = BTGATT_DB_CHARACTERISTIC;
- ras_control_point.properties = GATT_CHAR_PROP_BIT_WRITE | GATT_CHAR_PROP_BIT_INDICATE;
+ ras_control_point.properties = GATT_CHAR_PROP_BIT_WRITE_NR | GATT_CHAR_PROP_BIT_INDICATE;
ras_control_point.permissions = GATT_PERM_WRITE_ENCRYPTED | key_mask;
service.push_back(ras_control_point);
service.push_back(ccc_descriptor);
diff --git a/system/bta/ras/ras_types.h b/system/bta/ras/ras_types.h
index 30e935a9fb..2e860bc2fc 100644
--- a/system/bta/ras/ras_types.h
+++ b/system/bta/ras/ras_types.h
@@ -32,6 +32,7 @@ static const uint16_t kRasControlPointCharacteristic16bit = 0x2C17;
static const uint16_t kRasRangingDataReadyCharacteristic16bit = 0x2C18;
static const uint16_t kRasRangingDataOverWrittenCharacteristic16bit = 0x2C19;
static const uint16_t kClientCharacteristicConfiguration16bit = 0x2902;
+static const uint16_t kDefaultGattMtu = 23;
static const bluetooth::Uuid kRangingService = bluetooth::Uuid::From16Bit(kRangingService16Bit);
static const bluetooth::Uuid kRasFeaturesCharacteristic =
diff --git a/system/bta/sys/bta_sys.h b/system/bta/sys/bta_sys.h
index e1a9e5e803..d02e1ff0bd 100644
--- a/system/bta/sys/bta_sys.h
+++ b/system/bta/sys/bta_sys.h
@@ -24,7 +24,6 @@
#ifndef BTA_SYS_H
#define BTA_SYS_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <chrono>
@@ -140,7 +139,7 @@ inline std::string BtaIdSysText(const tBTA_SYS_ID& sys_id) {
CASE_RETURN_TEXT(BTA_ID_SDP);
CASE_RETURN_TEXT(BTA_ID_BLUETOOTH_MAX);
default:
- return base::StringPrintf("Unknown[%hhu]", sys_id);
+ return std::format("Unknown[{}]", static_cast<uint8_t>(sys_id));
}
}
diff --git a/system/bta/test/common/bta_gatt_queue_mock.cc b/system/bta/test/common/bta_gatt_queue_mock.cc
index 9c0d048a71..d4b3b9b0a2 100644
--- a/system/bta/test/common/bta_gatt_queue_mock.cc
+++ b/system/bta/test/common/bta_gatt_queue_mock.cc
@@ -49,8 +49,9 @@ void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) {
gatt_queue->ConfigureMtu(conn_id, mtu);
}
-void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi,
+bool BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id, tBTA_GATTC_MULTI& p_read_multi,
GATT_READ_MULTI_OP_CB cb, void* cb_data) {
bluetooth::log::assert_that(gatt_queue, "Mock GATT queue not set!");
gatt_queue->ReadMultiCharacteristic(conn_id, p_read_multi, cb, cb_data);
+ return true;
}
diff --git a/system/bta/vc/device.cc b/system/bta/vc/device.cc
index d1d9611a23..a0c41029df 100644
--- a/system/bta/vc/device.cc
+++ b/system/bta/vc/device.cc
@@ -36,6 +36,7 @@
#include "gatt/database.h"
#include "gattdefs.h"
#include "stack/btm/btm_sec.h"
+#include "stack/gatt/gatt_int.h"
#include "stack/include/bt_types.h"
#include "stack/include/gatt_api.h"
#include "types/bluetooth/uuid.h"
@@ -421,48 +422,67 @@ void VolumeControlDevice::EnqueueRemainingRequests(tGATT_IF /*gatt_if*/,
GATT_READ_OP_CB chrc_read_cb,
GATT_READ_MULTI_OP_CB chrc_multi_read_cb,
GATT_WRITE_OP_CB /*cccd_write_cb*/) {
- std::vector<uint16_t> handles_to_read;
+ const auto is_eatt_supported = gatt_profile_get_eatt_support_by_conn_id(connection_id);
- for (auto const& input : audio_inputs.volume_audio_inputs) {
- handles_to_read.push_back(input.state_handle);
- handles_to_read.push_back(input.gain_setting_handle);
- handles_to_read.push_back(input.type_handle);
- handles_to_read.push_back(input.status_handle);
- handles_to_read.push_back(input.description_handle);
- }
+ /* List of handles to the attributes having known and fixed-size values to read using the
+ * ATT_READ_MULTIPLE_REQ. The `.second` component contains 1 octet for the length + the actual
+ * attribute value length, exactly as in the received HCI packet for ATT_READ_MULTIPLE_RSP.
+ * We use this to make sure the request response will fit the current MTU size.
+ */
+ std::list<std::pair<uint16_t, size_t>> handles_to_read;
+
+ /* Variable-length attributes - always read using the regular read requests to automatically
+ * handle truncation in the GATT layer if MTU is to small to fit even a single complete value.
+ */
+ std::vector<uint16_t> handles_to_read_variable_length;
for (auto const& offset : audio_offsets.volume_offsets) {
- handles_to_read.push_back(offset.state_handle);
- handles_to_read.push_back(offset.audio_location_handle);
- handles_to_read.push_back(offset.audio_descr_handle);
+ handles_to_read.push_back(std::make_pair(offset.state_handle, 4));
+ handles_to_read.push_back(std::make_pair(offset.audio_location_handle, 5));
+ handles_to_read_variable_length.push_back(offset.audio_descr_handle);
}
- log::debug("{}, number of handles={}", address, handles_to_read.size());
+ for (auto const& input : audio_inputs.volume_audio_inputs) {
+ handles_to_read.push_back(std::make_pair(input.state_handle, 5));
+ handles_to_read.push_back(std::make_pair(input.gain_setting_handle, 4));
+ handles_to_read.push_back(std::make_pair(input.type_handle, 2));
+ handles_to_read.push_back(std::make_pair(input.status_handle, 2));
+ handles_to_read_variable_length.push_back(input.description_handle);
+ }
+
+ log::debug("{}, number of fixed-size attribute handles={}", address, handles_to_read.size());
+ log::debug("{}, number of variable-size attribute handles={}", address,
+ handles_to_read_variable_length.size());
+
+ if (com::android::bluetooth::flags::le_ase_read_multiple_variable() && is_eatt_supported) {
+ const size_t payload_limit = this->mtu_ - 1;
+
+ auto pair_it = handles_to_read.begin();
+ while (pair_it != handles_to_read.end()) {
+ tBTA_GATTC_MULTI multi_read{.num_attr = 0};
+ size_t size_limit = 0;
+
+ // Send at once just enough attributes to stay below the MTU size limit for the response
+ while ((pair_it != handles_to_read.end()) && (size_limit + pair_it->second < payload_limit) &&
+ (multi_read.num_attr < GATT_MAX_READ_MULTI_HANDLES)) {
+ multi_read.handles[multi_read.num_attr] = pair_it->first;
+ size_limit += pair_it->second;
+ ++multi_read.num_attr;
+ ++pair_it;
+ }
- if (!com::android::bluetooth::flags::le_ase_read_multiple_variable()) {
- for (auto const& handle : handles_to_read) {
+ log::debug{"{}, calling multi-read with {} attributes, {} left", address, multi_read.num_attr,
+ std::distance(pair_it, handles_to_read.end())};
+ BtaGattQueue::ReadMultiCharacteristic(connection_id, multi_read, chrc_multi_read_cb, nullptr);
+ }
+ } else {
+ for (auto const& [handle, _] : handles_to_read) {
BtaGattQueue::ReadCharacteristic(connection_id, handle, chrc_read_cb, nullptr);
}
- return;
}
- size_t sent_cnt = 0;
-
- while (sent_cnt < handles_to_read.size()) {
- tBTA_GATTC_MULTI multi_read{};
- size_t remain_cnt = (handles_to_read.size() - sent_cnt);
-
- multi_read.num_attr =
- remain_cnt > GATT_MAX_READ_MULTI_HANDLES ? GATT_MAX_READ_MULTI_HANDLES : remain_cnt;
-
- auto handles_begin = handles_to_read.begin() + sent_cnt;
- std::copy(handles_begin, handles_begin + multi_read.num_attr, multi_read.handles);
-
- sent_cnt += multi_read.num_attr;
- log::debug{"{}, calling multi with {} attributes, sent_cnt {} ", address, multi_read.num_attr,
- sent_cnt};
-
- BtaGattQueue::ReadMultiCharacteristic(connection_id, multi_read, chrc_multi_read_cb, nullptr);
+ for (auto const& handle : handles_to_read_variable_length) {
+ BtaGattQueue::ReadCharacteristic(connection_id, handle, chrc_read_cb, nullptr);
}
}
diff --git a/system/bta/vc/devices.h b/system/bta/vc/devices.h
index 19f2bd5650..4c0a105ee8 100644
--- a/system/bta/vc/devices.h
+++ b/system/bta/vc/devices.h
@@ -25,7 +25,6 @@
#include "bta/include/bta_gatt_api.h"
#include "bta/vc/types.h"
-#include "common/interfaces/ILoggable.h"
#include "os/logging/log_adapter.h"
#include "types/raw_address.h"
@@ -33,7 +32,7 @@ namespace bluetooth {
namespace vc {
namespace internal {
-class VolumeControlDevice : public bluetooth::common::IRedactableLoggable {
+class VolumeControlDevice {
public:
RawAddress address;
@@ -48,6 +47,7 @@ public:
uint8_t flags;
tCONN_ID connection_id;
+ uint16_t mtu_ = GATT_DEF_BLE_MTU_SIZE;
/* Volume Control Service */
uint16_t volume_state_handle;
@@ -81,15 +81,13 @@ public:
~VolumeControlDevice() = default;
- std::string ToStringForLogging() const override { return address.ToStringForLogging(); }
+ std::string ToStringForLogging() const { return address.ToStringForLogging(); }
- std::string ToRedactedStringForLogging() const override {
- return address.ToRedactedStringForLogging();
- }
+ std::string ToRedactedStringForLogging() const { return address.ToRedactedStringForLogging(); }
void DebugDump(int fd) {
std::stringstream stream;
- stream << " == device address: " << ADDRESS_TO_LOGGABLE_STR(address) << " == \n";
+ stream << " == device address: " << address.ToRedactedStringForLogging() << " == \n";
if (connection_id == GATT_INVALID_CONN_ID) {
stream << " Not connected\n";
diff --git a/system/bta/vc/devices_test.cc b/system/bta/vc/devices_test.cc
index fea281c701..15dd527e2b 100644
--- a/system/bta/vc/devices_test.cc
+++ b/system/bta/vc/devices_test.cc
@@ -692,25 +692,39 @@ TEST_F(VolumeControlDeviceTest, test_enqueue_remaining_requests_multiread) {
tGATT_IF gatt_if = 0x0001;
std::vector<uint8_t> register_for_notification_data({0x01, 0x00});
+ // The amount of attributes read at once is limited by the MTU size - 1 (here 22)
tBTA_GATTC_MULTI expected_to_read_part_1 = {
- .num_attr = 10,
+ .num_attr = 4,
.handles = {0x0022 /* audio input state 1 */, 0x0025 /* gain setting properties 1 */,
- 0x0027 /* audio input type 1 */, 0x0029 /* audio input status 1 */,
- 0x002e /* audio input description 1 */, 0x0042 /* audio input state 2 */,
- 0x0045 /* gain setting properties 2 */, 0x0047 /* audio input type 2 */,
- 0x0049 /* audio input status 2 */, 0x004e /* audio input description 2 */},
+ 0x0027 /* audio input type 1 */, 0x0029 /* audio input status 1 */},
};
tBTA_GATTC_MULTI expected_to_read_part_2 = {
- .num_attr = 6,
- .handles = {0x0062 /* audio output state 1 */, 0x0065 /* audio output location 1 */,
- 0x0069 /* audio output description 1 */, 0x0082 /* audio output state 1 */,
- 0x0085 /* audio output location 1 */,
- 0x008a /* audio output description 1 */},
+ .num_attr = 5,
+ .handles = {0x0042 /* audio input state 2 */, 0x0045 /* gain setting properties 2 */,
+ 0x0047 /* audio input type 2 */, 0x0049 /* audio input status 2 */,
+ 0x0062 /* audio output state 1 */},
};
+ tBTA_GATTC_MULTI expected_to_read_part_3 = {
+ .num_attr = 3,
+ .handles = {0x0065 /* audio output location 1 */, 0x0082 /* audio output state 1 */,
+ 0x0085 /* audio output location 1 */},
+ };
+
+ uint16_t expected_audio_input_description_1 = 0x002e;
+ uint16_t expected_audio_input_description_2 = 0x004e;
+ uint16_t expected_audio_output_description_1 = 0x0069;
+ uint16_t expected_audio_output_description_2 = 0x008a;
+
tBTA_GATTC_MULTI received_to_read_part_1{};
tBTA_GATTC_MULTI received_to_read_part_2{};
+ tBTA_GATTC_MULTI received_to_read_part_3{};
+
+ uint16_t audio_input_description_1 = 0;
+ uint16_t audio_input_description_2 = 0;
+ uint16_t audio_output_description_1 = 0;
+ uint16_t audio_output_description_2 = 0;
{
testing::InSequence s;
@@ -719,6 +733,16 @@ TEST_F(VolumeControlDeviceTest, test_enqueue_remaining_requests_multiread) {
.WillOnce(SaveArg<1>(&received_to_read_part_1));
EXPECT_CALL(gatt_queue, ReadMultiCharacteristic(_, _, _, _))
.WillOnce(SaveArg<1>(&received_to_read_part_2));
+ EXPECT_CALL(gatt_queue, ReadMultiCharacteristic(_, _, _, _))
+ .WillOnce(SaveArg<1>(&received_to_read_part_3));
+ EXPECT_CALL(gatt_queue, ReadCharacteristic(_, _, _, _))
+ .WillOnce(SaveArg<1>(&audio_output_description_1));
+ EXPECT_CALL(gatt_queue, ReadCharacteristic(_, _, _, _))
+ .WillOnce(SaveArg<1>(&audio_output_description_2));
+ EXPECT_CALL(gatt_queue, ReadCharacteristic(_, _, _, _))
+ .WillOnce(SaveArg<1>(&audio_input_description_1));
+ EXPECT_CALL(gatt_queue, ReadCharacteristic(_, _, _, _))
+ .WillOnce(SaveArg<1>(&audio_input_description_2));
}
EXPECT_CALL(gatt_queue, WriteDescriptor(_, _, _, GATT_WRITE, _, _)).Times(0);
EXPECT_CALL(gatt_interface, RegisterForNotifications(_, _, _)).Times(0);
@@ -738,6 +762,12 @@ TEST_F(VolumeControlDeviceTest, test_enqueue_remaining_requests_multiread) {
ASSERT_EQ(expected_to_read_part_1.num_attr, received_to_read_part_1.num_attr);
ASSERT_EQ(expected_to_read_part_2.num_attr, received_to_read_part_2.num_attr);
+ ASSERT_EQ(expected_to_read_part_3.num_attr, received_to_read_part_3.num_attr);
+
+ EXPECT_EQ(expected_audio_input_description_1, audio_input_description_1);
+ EXPECT_EQ(expected_audio_input_description_2, audio_input_description_2);
+ EXPECT_EQ(expected_audio_output_description_1, audio_output_description_1);
+ EXPECT_EQ(expected_audio_output_description_2, audio_output_description_2);
}
TEST_F(VolumeControlDeviceTest, test_check_link_encrypted) {
diff --git a/system/bta/vc/vc.cc b/system/bta/vc/vc.cc
index cf9fee3387..c381f1210a 100644
--- a/system/bta/vc/vc.cc
+++ b/system/bta/vc/vc.cc
@@ -176,7 +176,7 @@ public:
}
void OnGattConnected(tGATT_STATUS status, tCONN_ID connection_id, tGATT_IF /*client_if*/,
- RawAddress address, tBT_TRANSPORT transport, uint16_t /*mtu*/) {
+ RawAddress address, tBT_TRANSPORT transport, uint16_t mtu) {
bluetooth::log::info("{}, conn_id=0x{:04x}, transport={}, status={}(0x{:02x})", address,
connection_id, bt_transport_text(transport), gatt_status_text(status),
status);
@@ -202,6 +202,7 @@ public:
}
device->connection_id = connection_id;
+ device->mtu_ = mtu;
/* Make sure to remove device from background connect.
* It will be added back if needed, when device got disconnected
@@ -275,6 +276,15 @@ public:
ClearDeviceInformationAndStartSearch(device);
}
+ void OnMtuChanged(tCONN_ID conn_id, uint16_t mtu) {
+ VolumeControlDevice* device = volume_control_devices_.FindByConnId(conn_id);
+ if (!device) {
+ bluetooth::log::error("Skipping unknown device conn_id: {}", conn_id);
+ return;
+ }
+ device->mtu_ = mtu;
+ }
+
void OnServiceDiscDoneEvent(const RawAddress& address) {
VolumeControlDevice* device = volume_control_devices_.FindByAddress(address);
if (!device) {
@@ -1461,6 +1471,7 @@ private:
device->Disconnect(gatt_if_);
RemoveDeviceFromOperationList(device->address);
+ device->mtu_ = GATT_DEF_BLE_MTU_SIZE;
if (notify) {
callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, device->address);
@@ -1545,6 +1556,10 @@ private:
OnServiceChangeEvent(p_data->service_changed.remote_bda);
break;
+ case BTA_GATTC_CFG_MTU_EVT:
+ OnMtuChanged(p_data->cfg_mtu.conn_id, p_data->cfg_mtu.mtu);
+ break;
+
case BTA_GATTC_SRVC_DISC_DONE_EVT:
OnServiceDiscDoneEvent(p_data->service_discovery_done.remote_bda);
break;
@@ -1599,14 +1614,13 @@ private:
instance->OnCharacteristicValueChanged(conn_id, status, hdl, len, ptr,
((index == (handles.num_attr - 1)) ? data : nullptr),
false);
-
position += len + 2; /* skip the length of data */
index++;
}
- if (handles.num_attr - 1 != index) {
+ if (handles.num_attr != index) {
bluetooth::log::warn("Attempted to read {} handles, but received just {} values",
- +handles.num_attr, index + 1);
+ +handles.num_attr, index);
}
}
};
diff --git a/system/btcore/src/hal_util.cc b/system/btcore/src/hal_util.cc
index 5c32ed6208..5acc399730 100644
--- a/system/btcore/src/hal_util.cc
+++ b/system/btcore/src/hal_util.cc
@@ -18,12 +18,9 @@
#include "btcore/include/hal_util.h"
-#include <base/strings/stringprintf.h>
#include <dlfcn.h>
#include <hardware/bluetooth.h>
-using base::StringPrintf;
-
extern bt_interface_t bluetoothInterface;
int hal_util_load_bt_library(const bt_interface_t** interface) {
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index d442e0c2cf..75494590fd 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -123,9 +123,6 @@ cc_library_static {
"src/btif_rc.cc",
"src/btif_vc.cc",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
local_include_dirs: [
"include",
],
@@ -201,6 +198,7 @@ cc_library_static {
"src/btif_sdp.cc",
"src/btif_sdp_server.cc",
"src/btif_sock.cc",
+ "src/btif_sock_hal.cc",
"src/btif_sock_l2cap.cc",
"src/btif_sock_logging.cc",
"src/btif_sock_rfc.cc",
@@ -213,9 +211,6 @@ cc_library_static {
"src/btif_util.cc",
"src/stack_manager.cc",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
target: {
android: {
whole_static_libs: [
@@ -308,7 +303,6 @@ cc_test {
"bluetooth_flags_c_lib_for_test",
"libFraunhoferAAC",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-for-tests",
"libbluetooth-types",
"libbluetooth_core_rs",
@@ -390,9 +384,6 @@ cc_test {
"test/btif_profile_queue_test.cc",
],
header_libs: ["libbluetooth_headers"],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
static_libs: [
"libbluetooth-types",
"libbluetooth_gd",
@@ -426,9 +417,6 @@ cc_test {
"test/btif_avrcp_audio_track_test.cc",
],
header_libs: ["libbluetooth_headers"],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
static_libs: [
"libbluetooth-types",
"libbluetooth_log",
@@ -516,6 +504,7 @@ cc_test {
static_libs: [
"libbluetooth-types",
"libbluetooth_core_rs_bridge",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-platform-protos-lite",
"libchrome",
@@ -574,10 +563,6 @@ cc_test {
":TestMockUdrv",
"test/btif_hh_test.cc",
],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
header_libs: ["libbluetooth_headers"],
aidl: {
libs: ["bluetooth_constants"],
@@ -607,6 +592,7 @@ cc_test {
"libbluetooth_core_rs_bridge",
"libbluetooth_crypto_toolbox",
"libbluetooth_gd",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-audio-hal-interface",
"libbt-common",
@@ -699,10 +685,6 @@ cc_test {
":TestMockUdrv",
"test/btif_core_test.cc",
],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
header_libs: ["libbluetooth_headers"],
aidl: {
libs: ["bluetooth_constants"],
diff --git a/system/btif/BUILD.gn b/system/btif/BUILD.gn
index 519237997a..38b8fa9c6a 100644
--- a/system/btif/BUILD.gn
+++ b/system/btif/BUILD.gn
@@ -75,6 +75,7 @@ static_library("btif") {
"src/btif_sdp.cc",
"src/btif_sdp_server.cc",
"src/btif_sock.cc",
+ "src/btif_sock_hal.cc",
"src/btif_sock_l2cap.cc",
"src/btif_sock_logging.cc",
"src/btif_sock_rfc.cc",
diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc
index d589607124..c9dd6e7b74 100644
--- a/system/btif/co/bta_av_co.cc
+++ b/system/btif/co/bta_av_co.cc
@@ -720,8 +720,7 @@ void BtaAvCo::SaveCodec(const RawAddress& peer_address, const uint8_t* new_codec
void BtaAvCo::GetPeerEncoderParameters(const RawAddress& peer_address,
tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) {
uint16_t min_mtu = 0xFFFF;
- log::assert_that(p_peer_params != nullptr, "Peer address {}",
- ADDRESS_TO_LOGGABLE_STR(peer_address));
+ log::assert_that(p_peer_params != nullptr, "Peer address {}", peer_address);
std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_);
@@ -1001,11 +1000,11 @@ void BtaAvCo::DebugDump(int fd) {
dprintf(fd, "\nA2DP Peers State:\n");
dprintf(fd, " Source: active peer: %s\n",
(bta_av_source_state_.getActivePeer() != nullptr)
- ? ADDRESS_TO_LOGGABLE_CSTR(bta_av_source_state_.getActivePeer()->addr)
+ ? bta_av_source_state_.getActivePeer()->addr.ToRedactedStringForLogging().c_str()
: "null");
dprintf(fd, " Sink: active peer: %s\n",
(bta_av_sink_state_.getActivePeer() != nullptr)
- ? ADDRESS_TO_LOGGABLE_CSTR(bta_av_sink_state_.getActivePeer()->addr)
+ ? bta_av_sink_state_.getActivePeer()->addr.ToRedactedStringForLogging().c_str()
: "null");
for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peer_cache_->peers_); i++) {
@@ -1013,7 +1012,7 @@ void BtaAvCo::DebugDump(int fd) {
if (peer.addr.IsEmpty()) {
continue;
}
- dprintf(fd, " Peer: %s\n", ADDRESS_TO_LOGGABLE_CSTR(peer.addr));
+ dprintf(fd, " Peer: %s\n", peer.addr.ToRedactedStringForLogging().c_str());
dprintf(fd, " Number of sinks: %u\n", peer.num_sinks);
dprintf(fd, " Number of sources: %u\n", peer.num_sources);
dprintf(fd, " Number of SEPs: %u\n", peer.num_seps);
diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h
index c55ddedec2..5ab2399b31 100644
--- a/system/btif/include/btif_hh.h
+++ b/system/btif/include/btif_hh.h
@@ -19,7 +19,6 @@
#ifndef BTIF_HH_H
#define BTIF_HH_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_hh.h>
@@ -74,7 +73,7 @@ inline std::string btif_hh_status_text(const BTIF_HH_STATUS& status) {
CASE_RETURN_TEXT(BTIF_HH_ENABLED);
CASE_RETURN_TEXT(BTIF_HH_DISABLING);
default:
- return base::StringPrintf("UNKNOWN[%u]", status);
+ return std::format("UNKNOWN[{}]", static_cast<unsigned>(status));
}
}
@@ -133,7 +132,7 @@ typedef struct {
btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
bool service_dereg_active;
- std::list<tAclLinkSpec> pending_connections;
+ std::list<tAclLinkSpec> new_connection_requests;
} btif_hh_cb_t;
/*******************************************************************************
diff --git a/system/gd/dumpsys/dumpsys_test_data.h b/system/btif/include/btif_sock_hal.h
index 763d702f48..9588110920 100644
--- a/system/gd/dumpsys/dumpsys_test_data.h
+++ b/system/btif/include/btif_sock_hal.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +15,7 @@
*/
#pragma once
-#include <string>
-namespace testing {
-const std::string& GetBundledSchemaData();
-} // namespace testing
+#include <hardware/bluetooth.h>
+
+bt_status_t btsock_hal_init();
diff --git a/system/btif/include/btif_sock_l2cap.h b/system/btif/include/btif_sock_l2cap.h
index c08ef532d7..3edcd35e32 100644
--- a/system/btif/include/btif_sock_l2cap.h
+++ b/system/btif/include/btif_sock_l2cap.h
@@ -22,20 +22,26 @@
#define BTIF_SOCK_L2CAP_H
#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
#include "btif_uid.h"
#include "types/raw_address.h"
bt_status_t btsock_l2cap_init(int handle, uid_set_t* set);
bt_status_t btsock_l2cap_cleanup();
-bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd, int flags,
- int app_uid);
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd, int flags, int app_uid,
+ btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size);
bt_status_t btsock_l2cap_connect(const RawAddress* bd_addr, int channel, int* sock_fd, int flags,
- int app_uid);
+ int app_uid, btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size);
void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id);
void on_l2cap_psm_assigned(int id, int psm);
bt_status_t btsock_l2cap_disconnect(const RawAddress* bd_addr);
bt_status_t btsock_l2cap_get_l2cap_local_cid(bluetooth::Uuid& conn_uuid, uint16_t* cid);
bt_status_t btsock_l2cap_get_l2cap_remote_cid(bluetooth::Uuid& conn_uuid, uint16_t* cid);
+bool btsock_l2cap_in_use(uint64_t socket_id);
+void on_btsocket_l2cap_opened_complete(uint64_t socket_id, bool success);
+void on_btsocket_l2cap_close(uint64_t socket_id);
#endif
diff --git a/system/btif/include/btif_sock_rfc.h b/system/btif/include/btif_sock_rfc.h
index a7b21aab52..eb5f22b82d 100644
--- a/system/btif/include/btif_sock_rfc.h
+++ b/system/btif/include/btif_sock_rfc.h
@@ -28,6 +28,8 @@
#define BTIF_SOCK_RFC_H
#include "btif_uid.h"
+#include "hardware/bluetooth.h"
+#include "hardware/bt_sock.h"
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
bt_status_t btsock_rfc_init(int handle, uid_set_t* set);
@@ -36,10 +38,17 @@ bt_status_t btsock_rfc_control_req(uint8_t dlci, const RawAddress& bd_addr, uint
uint8_t break_signal, uint8_t discard_buffers,
uint8_t break_signal_seq, bool fc);
bt_status_t btsock_rfc_listen(const char* name, const bluetooth::Uuid* uuid, int channel,
- int* sock_fd, int flags, int app_uid);
+ int* sock_fd, int flags, int app_uid, btsock_data_path_t data_path,
+ const char* socket_name, uint64_t hub_id, uint64_t endpoint_id,
+ int max_rx_packet_size);
bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, const bluetooth::Uuid* uuid, int channel,
- int* sock_fd, int flags, int app_uid);
+ int* sock_fd, int flags, int app_uid, btsock_data_path_t data_path,
+ const char* socket_name, uint64_t hub_id, uint64_t endpoint_id,
+ int max_rx_packet_size);
void btsock_rfc_signaled(int fd, int flags, uint32_t user_id);
bt_status_t btsock_rfc_disconnect(const RawAddress* bd_addr);
+bool btsock_rfc_in_use(uint64_t socket_id);
+void on_btsocket_rfc_opened_complete(uint64_t socket_id, bool success);
+void on_btsocket_rfc_close(uint64_t socket_id);
#endif
diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc
index 77a492f68d..3abbb1122c 100644
--- a/system/btif/src/bluetooth.cc
+++ b/system/btif/src/bluetooth.cc
@@ -877,7 +877,7 @@ static int set_event_filter_connection_setup_all_devices() {
return BT_STATUS_SUCCESS;
}
-static void dump(int fd, const char** arguments) {
+static void dump(int fd, const char** /*arguments*/) {
log::debug("Started bluetooth dumpsys");
btif_debug_conn_dump(fd);
btif_debug_bond_event_dump(fd);
@@ -911,7 +911,7 @@ static void dump(int fd, const char** arguments) {
DumpsysRecord(fd);
L2CA_Dumpsys(fd);
DumpsysBtm(fd);
- bluetooth::shim::Dump(fd, arguments);
+ bluetooth::shim::Dump(fd);
power_telemetry::GetInstance().Dumpsys(fd);
log::debug("Finished bluetooth dumpsys");
}
diff --git a/system/btif/src/btif_a2dp.cc b/system/btif/src/btif_a2dp.cc
index c572a34e2b..d643d199a2 100644
--- a/system/btif/src/btif_a2dp.cc
+++ b/system/btif/src/btif_a2dp.cc
@@ -148,14 +148,7 @@ void btif_a2dp_on_offload_started(const RawAddress& peer_addr, tBTA_AV_STATUS st
if (btif_av_is_a2dp_offload_running()) {
if (ack != Status::SUCCESS && btif_av_stream_started_ready(A2dpType::kSource)) {
log::error("peer {} offload start failed", peer_addr);
- if (com::android::bluetooth::flags::stop_on_offload_fail()) {
- btif_av_stream_stop(peer_addr);
- } else {
- // Offload request will return with failure from btif_av sm if
- // suspend is triggered for remote start. Disconnect only if SoC
- // returned failure for offload VSC
- btif_av_source_disconnect(peer_addr);
- }
+ btif_av_stream_stop(peer_addr);
}
}
diff --git a/system/btif/src/btif_a2dp_sink.cc b/system/btif/src/btif_a2dp_sink.cc
index 2d214b0521..02b92621ed 100644
--- a/system/btif/src/btif_a2dp_sink.cc
+++ b/system/btif/src/btif_a2dp_sink.cc
@@ -540,7 +540,6 @@ static void btif_a2dp_sink_audio_handle_stop_decoding() {
}
static void btif_decode_alarm_cb(void* /* context */) {
- LockGuard lock(g_mutex);
btif_a2dp_sink_cb.worker_thread.DoInThread(FROM_HERE,
base::BindOnce(btif_a2dp_sink_avk_handle_timer));
}
diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc
index a7ba4fa0dc..d58e3de696 100644
--- a/system/btif/src/btif_a2dp_source.cc
+++ b/system/btif/src/btif_a2dp_source.cc
@@ -356,8 +356,7 @@ class A2dpStreamCallbacks : public bluetooth::audio::a2dp::StreamCallbacks {
}
// Check if LE Audio is currently active.
- if (com::android::bluetooth::flags::a2dp_check_lea_iso_channel() &&
- hci::IsoManager::GetInstance()->GetNumberOfActiveIso() > 0) {
+ if (hci::IsoManager::GetInstance()->GetNumberOfActiveIso() > 0) {
log::error("unable to start stream: LEA is active");
return Status::FAILURE;
}
@@ -575,8 +574,13 @@ void btif_a2dp_source_shutdown(std::promise<void> shutdown_complete_promise) {
/* Make sure no channels are restarted while shutting down */
btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateShuttingDown);
- local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed,
- std::move(shutdown_complete_promise)));
+ // TODO(b/374166531) Remove the check for get_main_thread.
+ if (local_thread() != get_main_thread()) {
+ local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed,
+ std::move(shutdown_complete_promise)));
+ } else {
+ btif_a2dp_source_shutdown_delayed(std::move(shutdown_complete_promise));
+ }
}
static void btif_a2dp_source_shutdown_delayed(std::promise<void> shutdown_complete_promise) {
diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc
index d40586461d..5a09cf2581 100644
--- a/system/btif/src/btif_av.cc
+++ b/system/btif/src/btif_av.cc
@@ -21,7 +21,6 @@
#include "btif/include/btif_av.h"
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/a2dp/enums.pb.h>
@@ -1076,7 +1075,7 @@ std::string BtifAvPeer::FlagsToString() const {
result = "None";
}
- return base::StringPrintf("0x%x(%s)", flags_, result.c_str());
+ return std::format("0x{:x}({})", flags_, result);
}
bt_status_t BtifAvPeer::Init() {
@@ -2810,7 +2809,7 @@ static void btif_av_source_initiate_av_open_timer_timeout(void* data) {
BtifAvPeer* peer = reinterpret_cast<BtifAvPeer*>(data);
bool device_connected = false;
- if (com::android::bluetooth::flags::avrcp_connect_a2dp_with_delay() && is_new_avrcp_enabled()) {
+ if (is_new_avrcp_enabled()) {
// check if device is connected
if (bluetooth::avrcp::AvrcpService::Get() != nullptr) {
device_connected =
@@ -3992,7 +3991,7 @@ static void btif_debug_av_peer_dump(int fd, const BtifAvPeer& peer) {
break;
}
- dprintf(fd, " Peer: %s\n", ADDRESS_TO_LOGGABLE_CSTR(peer.PeerAddress()));
+ dprintf(fd, " Peer: %s\n", peer.PeerAddress().ToRedactedStringForLogging().c_str());
dprintf(fd, " Connected: %s\n", peer.IsConnected() ? "true" : "false");
dprintf(fd, " Streaming: %s\n", peer.IsStreaming() ? "true" : "false");
dprintf(fd, " SEP: %d(%s)\n", peer.PeerSep(), (peer.IsSource()) ? "Source" : "Sink");
@@ -4018,7 +4017,8 @@ static void btif_debug_av_source_dump(int fd) {
if (!enabled) {
return;
}
- dprintf(fd, " Active peer: %s\n", ADDRESS_TO_LOGGABLE_CSTR(btif_av_source.ActivePeer()));
+ dprintf(fd, " Active peer: %s\n",
+ btif_av_source.ActivePeer().ToRedactedStringForLogging().c_str());
dprintf(fd, " Peers:\n");
btif_av_source.DumpPeersInfo(fd);
}
@@ -4030,7 +4030,8 @@ static void btif_debug_av_sink_dump(int fd) {
if (!enabled) {
return;
}
- dprintf(fd, " Active peer: %s\n", ADDRESS_TO_LOGGABLE_CSTR(btif_av_sink.ActivePeer()));
+ dprintf(fd, " Active peer: %s\n",
+ btif_av_sink.ActivePeer().ToRedactedStringForLogging().c_str());
dprintf(fd, " Peers:\n");
btif_av_sink.DumpPeersInfo(fd);
}
diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc
index 73fe810e23..9164e53ef7 100644
--- a/system/btif/src/btif_core.cc
+++ b/system/btif/src/btif_core.cc
@@ -53,6 +53,7 @@
#include "device/include/device_iot_config.h"
#include "hci/controller_interface.h"
#include "internal_include/bt_target.h"
+#include "lpp/lpp_offload_interface.h"
#include "main/shim/entry.h"
#include "main/shim/helpers.h"
#include "osi/include/allocator.h"
@@ -510,6 +511,16 @@ void btif_get_adapter_property(bt_property_type_t type) {
log::verbose("Don't support Dynamic Audio Buffer");
}
}
+ } else if (prop.type == BT_PROPERTY_LPP_OFFLOAD_FEATURES) {
+ bt_lpp_offload_features_t lpp_offload_features;
+ hal::SocketCapabilities socket_offload_capabilities =
+ bluetooth::shim::GetLppOffloadManager()->GetSocketCapabilities();
+ lpp_offload_features.number_of_supported_offloaded_le_coc_sockets =
+ socket_offload_capabilities.le_coc_capabilities.number_of_supported_sockets;
+ lpp_offload_features.number_of_supported_offloaded_rfcomm_sockets =
+ socket_offload_capabilities.rfcomm_capabilities.number_of_supported_sockets;
+ prop.len = sizeof(bt_lpp_offload_features_t);
+ memcpy(prop.val, &lpp_offload_features, prop.len);
} else {
status = btif_storage_get_adapter_property(&prop);
}
diff --git a/system/btif/src/btif_debug_conn.cc b/system/btif/src/btif_debug_conn.cc
index ef2843baf3..935758a876 100644
--- a/system/btif/src/btif_debug_conn.cc
+++ b/system/btif/src/btif_debug_conn.cc
@@ -90,7 +90,7 @@ void btif_debug_conn_dump(int fd) {
while (connection_events[dump_event].ts) {
conn_event_t* evt = &connection_events[dump_event];
dprintf(fd, " %s %s %s", format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)),
- format_state(evt->state), ADDRESS_TO_LOGGABLE_CSTR(evt->bda));
+ format_state(evt->state), evt->bda.ToRedactedStringForLogging().c_str());
if (evt->state == BTIF_DEBUG_DISCONNECTED) {
dprintf(fd, " reason=%d", evt->disconnect_reason);
}
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 8ed9face97..670889006b 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -31,7 +31,6 @@
#include "btif_dm.h"
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <hardware/bluetooth.h>
@@ -69,6 +68,7 @@
#include "hci/le_rand_callback.h"
#include "internal_include/bt_target.h"
#include "internal_include/stack_config.h"
+#include "main/shim/acl_api.h"
#include "main/shim/entry.h"
#include "main/shim/helpers.h"
#include "main/shim/le_advertising_manager.h"
@@ -231,7 +231,7 @@ typedef struct {
#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
-#define MAX_BTIF_BOND_EVENT_ENTRIES 15
+#define MAX_BTIF_BOND_EVENT_ENTRIES 31
#define MAX_NUM_DEVICES_IN_EIR_UUID_CACHE 128
@@ -551,10 +551,8 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr,
if (!pairing_cb.static_bdaddr.IsEmpty()) {
BTM_LogHistory(
kBtmLogTagCallback, bd_addr, "Bond state changed",
- base::StringPrintf(
- "Crosskey bt_status:%s bond_state:%u reason:%s",
- bt_status_text(status).c_str(), state,
- hci_reason_code_text(to_hci_reason_code(pairing_cb.fail_reason)).c_str()));
+ std::format("Crosskey bt_status:{} bond_state:{} reason:{}", bt_status_text(status),
+ state, hci_reason_code_text(to_hci_reason_code(pairing_cb.fail_reason))));
GetInterfaceToProfiles()->events->invoke_bond_state_changed_cb(status, bd_addr, state,
pairing_cb.fail_reason);
}
@@ -581,11 +579,9 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr,
log::error("Fail to save metric id for device:{}", bd_addr);
}
}
- BTM_LogHistory(
- kBtmLogTagCallback, bd_addr, "Bond state changed",
- base::StringPrintf(
- "bt_status:%s bond_state:%u reason:%s", bt_status_text(status).c_str(), state,
- hci_reason_code_text(to_hci_reason_code(pairing_cb.fail_reason)).c_str()));
+ BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Bond state changed",
+ std::format("bt_status:{} bond_state:{} reason:{}", bt_status_text(status), state,
+ hci_reason_code_text(to_hci_reason_code(pairing_cb.fail_reason))));
GetInterfaceToProfiles()->events->invoke_bond_state_changed_cb(status, bd_addr, state,
pairing_cb.fail_reason);
@@ -974,9 +970,9 @@ static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) {
}
}
BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Pin request",
- base::StringPrintf("name:\"%s\" min16:%c",
- PRIVATE_NAME(reinterpret_cast<char const*>(bd_name.name)),
- (p_pin_req->min_16_digit) ? 'T' : 'F'));
+ std::format("name:\"{}\" min16:{:c}",
+ PRIVATE_NAME(reinterpret_cast<char const*>(bd_name.name)),
+ (p_pin_req->min_16_digit) ? 'T' : 'F'));
GetInterfaceToProfiles()->events->invoke_pin_request_cb(bd_addr, bd_name, cod,
p_pin_req->min_16_digit);
}
@@ -1047,12 +1043,11 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) {
pairing_cb.sdp_attempts = 0;
BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Ssp request",
- base::StringPrintf("just_works:%c pin:%u", (p_ssp_cfm_req->just_works) ? 'T' : 'F',
- p_ssp_cfm_req->num_val));
+ std::format("just_works:{:c} pin:{}", (p_ssp_cfm_req->just_works) ? 'T' : 'F',
+ p_ssp_cfm_req->num_val));
GetInterfaceToProfiles()->events->invoke_ssp_request_cb(
bd_addr,
- (p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT
- : BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+ p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT : BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
p_ssp_cfm_req->num_val);
}
@@ -1078,7 +1073,7 @@ static void btif_dm_ssp_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) {
pairing_cb.is_ssp = true;
BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Ssp request",
- base::StringPrintf("passkey:%u", p_ssp_key_notif->passkey));
+ std::format("passkey:{}", p_ssp_key_notif->passkey));
GetInterfaceToProfiles()->events->invoke_ssp_request_cb(
bd_addr, BT_SSP_VARIANT_PASSKEY_NOTIFICATION, p_ssp_key_notif->passkey);
}
@@ -1209,9 +1204,8 @@ static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
if (is_crosskey) {
// If bonding occurred due to cross-key pairing, send address
// consolidate callback
- BTM_LogHistory(
- kBtmLogTagCallback, bd_addr, "Consolidate",
- base::StringPrintf(" <=> %s", ADDRESS_TO_LOGGABLE_CSTR(pairing_cb.bd_addr)));
+ BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Consolidate",
+ std::format("<=> {}", pairing_cb.bd_addr));
GetInterfaceToProfiles()->events->invoke_address_consolidate_cb(pairing_cb.bd_addr,
bd_addr);
} else {
@@ -1683,9 +1677,8 @@ static void btif_on_service_discovery_results(RawAddress bd_addr,
const tBTA_STATUS bta_status = result;
BTM_LogHistory(kBtmLogTagSdp, bd_addr, "Discovered services",
- base::StringPrintf("bta_status:%s sdp_uuids:%zu eir_uuids:%zu",
- bta_status_text(bta_status).c_str(), uuids_param.size(),
- num_eir_uuids));
+ std::format("bta_status:{} sdp_uuids:{} eir_uuids:{}", bta_status_text(bta_status),
+ uuids_param.size(), num_eir_uuids));
if (!uuids_param.empty() || num_eir_uuids != 0) {
/* Also write this to the NVRAM */
@@ -1967,6 +1960,22 @@ void BTIF_dm_enable() {
pairing_cb = {};
pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+ /* Bluetooth Core Specification version 5.4
+ * 7.8.5 LE Set Advertising Parameters command
+ * 7.8.53 LE Set Extended Advertising Parameters command
+ * 7.8.64 LE Set Extended Scan Parameters command
+ * 7.8.12 LE Create Connection command
+ * 7.8.66 LE Extended Create Connection command
+ * Set all-zero set to resolving list to make controller generate RPA for
+ * un-direct (broadcast) advertising RPA */
+ if (bluetooth::shim::GetController()->IsRpaGenerationSupported()) {
+ log::info("Support RPA offload, set all-zero set in resolving list");
+ tBLE_BD_ADDR all_zero_address_with_type = {0};
+ const Octet16 all_zero_peer_irk = {0};
+ bluetooth::shim::ACL_AddToAddressResolution(all_zero_address_with_type, all_zero_peer_irk,
+ ble_local_key_cb.id_keys.irk);
+ }
+
// Enable address consolidation.
btif_storage_load_le_devices();
@@ -2257,6 +2266,9 @@ void btif_dm_acl_evt(tBTA_DM_ACL_EVT event, tBTA_DM_ACL* p_data) {
case BTA_DM_LE_FEATURES_READ:
btif_get_adapter_property(BT_PROPERTY_LOCAL_LE_FEATURES);
break;
+ case BTA_DM_LPP_OFFLOAD_FEATURES_READ:
+ btif_get_adapter_property(BT_PROPERTY_LPP_OFFLOAD_FEATURES);
+ break;
default: {
log::error("Unexpected tBTA_DM_ACL_EVT:{}", event);
@@ -2313,9 +2325,9 @@ static void bta_energy_info_cb(tBTM_BLE_TX_TIME_MS tx_time, tBTM_BLE_RX_TIME_MS
void btif_dm_start_discovery(void) {
log::verbose("start device discover/inquiry");
- BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Device discovery",
- base::StringPrintf("is_request_queued:%c",
- bta_dm_is_search_request_queued() ? 'T' : 'F'));
+ BTM_LogHistory(
+ kBtmLogTag, RawAddress::kEmpty, "Device discovery",
+ std::format("is_request_queued:{:c}", bta_dm_is_search_request_queued() ? 'T' : 'F'));
/* no race here because we're guaranteed to be in the main thread */
if (bta_dm_is_search_request_queued()) {
@@ -2357,7 +2369,7 @@ void btif_dm_create_bond(const RawAddress bd_addr, tBT_TRANSPORT transport) {
log::verbose("bd_addr={}, transport={}", bd_addr, transport);
BTM_LogHistory(kBtmLogTag, bd_addr, "Create bond",
- base::StringPrintf("transport:%s", bt_transport_text(transport).c_str()));
+ std::format("transport:{}", bt_transport_text(transport)));
btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND, pairing_cb.state);
@@ -2379,7 +2391,7 @@ void btif_dm_create_bond_le(const RawAddress bd_addr, tBLE_ADDR_TYPE addr_type)
.bda = bd_addr,
};
BTM_LogHistory(kBtmLogTag, ble_bd_addr, "Create bond",
- base::StringPrintf("transport:%s", bt_transport_text(BT_TRANSPORT_LE).c_str()));
+ std::format("transport:{}", bt_transport_text(BT_TRANSPORT_LE)));
btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND, pairing_cb.state);
@@ -2418,8 +2430,8 @@ void btif_dm_create_bond_out_of_band(const RawAddress bd_addr, tBT_TRANSPORT tra
}
BTM_LogHistory(kBtmLogTag, bd_addr, "Create bond",
- base::StringPrintf("transport:%s oob:%s", bt_transport_text(transport).c_str(),
- btm_oob_data_text(oob_cb.data_present).c_str()));
+ std::format("transport:{} oob:{}", bt_transport_text(transport),
+ btm_oob_data_text(oob_cb.data_present)));
uint8_t empty[] = {0, 0, 0, 0, 0, 0, 0};
switch (transport) {
@@ -2628,12 +2640,11 @@ void btif_dm_pin_reply(const RawAddress bd_addr, uint8_t accept, uint8_t pin_len
******************************************************************************/
void btif_dm_ssp_reply(const RawAddress bd_addr, bt_ssp_variant_t variant, uint8_t accept) {
log::verbose("accept={}", accept);
- BTM_LogHistory(
- kBtmLogTag, bd_addr, "Ssp reply",
- base::StringPrintf("originator:%s variant:%d accept:%c le:%c numeric_comparison:%c",
- (pairing_cb.is_local_initiated) ? "local" : "remote", variant,
- (accept) ? 'Y' : 'N', (pairing_cb.is_le_only) ? 'T' : 'F',
- (pairing_cb.is_le_nc) ? 'T' : 'F'));
+ BTM_LogHistory(kBtmLogTag, bd_addr, "Ssp reply",
+ std::format("originator:{} variant:{} accept:{:c} le:{:c} numeric_comparison:{:c}",
+ pairing_cb.is_local_initiated ? "local" : "remote", variant,
+ accept ? 'Y' : 'N', pairing_cb.is_le_only ? 'T' : 'F',
+ pairing_cb.is_le_nc ? 'T' : 'F'));
if (pairing_cb.is_le_only) {
if (pairing_cb.is_le_nc) {
BTA_DmBleConfirmReply(bd_addr, accept);
@@ -2816,7 +2827,7 @@ void btif_dm_get_remote_services(RawAddress remote_addr, const tBT_TRANSPORT tra
log::verbose("transport={}, remote_addr={}", bt_transport_text(transport), remote_addr);
BTM_LogHistory(kBtmLogTag, remote_addr, "Service discovery",
- base::StringPrintf("transport:%s", bt_transport_text(transport).c_str()));
+ std::format("transport:{}", bt_transport_text(transport)));
BTA_DmDiscover(remote_addr,
service_discovery_callbacks{
@@ -3070,7 +3081,7 @@ static void id_status_callback(tBT_TRANSPORT transport, bool is_valid, const Oct
auto advertiser = bluetooth::shim::get_ble_advertiser_instance();
::AdvertiseParameters parameters{};
- parameters.advertising_event_properties = 0x0045 /* connectable, discoverable, tx power */;
+ parameters.advertising_event_properties = 0x0041 /* connectable, tx power */;
parameters.min_interval = 0xa0; // 100 ms
parameters.max_interval = 0x500; // 800 ms
parameters.channel_map = 0x7; // Use all the channels
@@ -3079,6 +3090,7 @@ static void id_status_callback(tBT_TRANSPORT transport, bool is_valid, const Oct
parameters.secondary_advertising_phy = 2;
parameters.scan_request_notification_enable = 0;
parameters.own_address_type = BLE_ADDR_RANDOM;
+ parameters.discoverable = true;
std::vector<uint8_t> advertisement{0x02, 0x01 /* Flags */, 0x02 /* Connectable */};
std::vector<uint8_t> scan_data{};
@@ -3233,7 +3245,7 @@ static void btif_dm_ble_passkey_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif)
pairing_cb.is_ssp = false;
BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Ssp request",
- base::StringPrintf("passkey:%u", p_ssp_key_notif->passkey));
+ std::format("passkey:{}", p_ssp_key_notif->passkey));
GetInterfaceToProfiles()->events->invoke_ssp_request_cb(
bd_addr, BT_SSP_VARIANT_PASSKEY_NOTIFICATION, p_ssp_key_notif->passkey);
@@ -3363,16 +3375,20 @@ static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
break;
case BTA_DM_AUTH_SMP_CONN_TOUT: {
- if (!p_auth_cmpl->is_ctkd && btm_sec_is_a_bonded_dev(bd_addr)) {
+ bool during_bonding =
+ (bd_addr == pairing_cb.bd_addr || bd_addr == pairing_cb.static_bdaddr);
+
+ if (during_bonding || p_auth_cmpl->is_ctkd || !btm_sec_is_a_bonded_dev(bd_addr)) {
+ log::info("Removing ble bonding keys on SMP_CONN_TOUT during_bonding: {}, is_ctkd: {}",
+ during_bonding, p_auth_cmpl->is_ctkd);
+ btif_dm_remove_ble_bonding_keys();
+ status = BT_STATUS_AUTH_FAILURE;
+ } else {
log::warn("Bonded device addr={}, timed out - will not remove the keys", bd_addr);
// Don't send state change to upper layers - otherwise Java think we
// unbonded, and will disconnect HID profile.
return;
}
- log::info("Removing ble bonding keys on SMP_CONN_TOUT during crosskey: {}",
- p_auth_cmpl->is_ctkd);
- btif_dm_remove_ble_bonding_keys();
- status = BT_STATUS_AUTH_FAILURE;
break;
}
case BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT:
@@ -3548,9 +3564,9 @@ static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ* p_pin_req) {
cod = COD_UNCLASSIFIED;
- BTM_LogHistory(kBtmLogTagCallback, bd_addr, "PIN request",
- base::StringPrintf("name:'%s'",
- PRIVATE_NAME(reinterpret_cast<char const*>(bd_name.name))));
+ BTM_LogHistory(
+ kBtmLogTagCallback, bd_addr, "PIN request",
+ std::format("name:'{}'", PRIVATE_NAME(reinterpret_cast<char const*>(bd_name.name))));
GetInterfaceToProfiles()->events->invoke_pin_request_cb(bd_addr, bd_name, cod, false);
}
@@ -3570,7 +3586,7 @@ static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req) {
pairing_cb.is_le_nc = true;
BTM_LogHistory(kBtmLogTagCallback, bd_addr, "Ssp request",
- base::StringPrintf("passkey:%u", p_notif_req->passkey));
+ std::format("passkey:{}", p_notif_req->passkey));
GetInterfaceToProfiles()->events->invoke_ssp_request_cb(
bd_addr, BT_SSP_VARIANT_PASSKEY_CONFIRMATION, p_notif_req->passkey);
@@ -3828,8 +3844,8 @@ void btif_debug_bond_event_dump(int fd) {
break;
}
- dprintf(fd, " %s %s %s %s\n", eventtime, ADDRESS_TO_LOGGABLE_CSTR(event->bd_addr),
- func_name, bond_state);
+ dprintf(fd, " %s %s %s %s\n", eventtime,
+ event->bd_addr.ToRedactedStringForLogging().c_str(), func_name, bond_state);
}
}
diff --git a/system/btif/src/btif_gatt_server.cc b/system/btif/src/btif_gatt_server.cc
index 558148e427..5af90205ba 100644
--- a/system/btif/src/btif_gatt_server.cc
+++ b/system/btif/src/btif_gatt_server.cc
@@ -292,46 +292,6 @@ static bt_status_t btif_gatts_unregister_app(int server_if) {
return do_in_jni_thread(Bind(&BTA_GATTS_AppDeregister, server_if));
}
-static void btif_gatts_open_impl(int server_if, const RawAddress& address, bool is_direct,
- tBT_TRANSPORT transport) {
- // Ensure device is in inquiry database
- tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC;
- int device_type = 0;
-
- if (btif_get_address_type(address, &addr_type) && btif_get_device_type(address, &device_type) &&
- device_type != BT_DEVICE_TYPE_BREDR) {
- BTA_DmAddBleDevice(address, addr_type, device_type);
- }
-
- // Determine transport
- if (transport == BT_TRANSPORT_AUTO) {
- switch (device_type) {
- case BT_DEVICE_TYPE_BREDR:
- transport = BT_TRANSPORT_BR_EDR;
- break;
-
- case BT_DEVICE_TYPE_BLE:
- transport = BT_TRANSPORT_LE;
- break;
-
- case BT_DEVICE_TYPE_DUMO:
- transport = BT_TRANSPORT_BR_EDR;
- break;
-
- default:
- log::error("Unknown device type {}", DeviceTypeText(device_type));
- // transport must not be AUTO for finding control blocks. Use LE for backward compatibility.
- transport = BT_TRANSPORT_LE;
- break;
- }
- }
-
- // Connect!
- BTA_GATTS_Open(server_if, address, BLE_ADDR_PUBLIC, is_direct, transport);
-}
-
-// Used instead of btif_gatts_open_impl if the flag
-// ble_gatt_server_use_address_type_in_connection is enabled.
static void btif_gatts_open_impl_use_address_type(int server_if, const RawAddress& address,
tBLE_ADDR_TYPE addr_type, bool is_direct,
tBT_TRANSPORT transport) {
@@ -369,13 +329,8 @@ static bt_status_t btif_gatts_open(int server_if, const RawAddress& bd_addr, uin
bool is_direct, int transport) {
CHECK_BTGATT_INIT();
- if (com::android::bluetooth::flags::ble_gatt_server_use_address_type_in_connection()) {
- return do_in_jni_thread(Bind(&btif_gatts_open_impl_use_address_type, server_if, bd_addr,
- addr_type, is_direct, to_bt_transport(transport)));
- } else {
- return do_in_jni_thread(
- Bind(&btif_gatts_open_impl, server_if, bd_addr, is_direct, to_bt_transport(transport)));
- }
+ return do_in_jni_thread(Bind(&btif_gatts_open_impl_use_address_type, server_if, bd_addr,
+ addr_type, is_direct, to_bt_transport(transport)));
}
static void btif_gatts_close_impl(int server_if, const RawAddress& address, int conn_id) {
diff --git a/system/btif/src/btif_hf.cc b/system/btif/src/btif_hf.cc
index 8edc70ab3d..bd607ea142 100644
--- a/system/btif/src/btif_hf.cc
+++ b/system/btif/src/btif_hf.cc
@@ -1416,9 +1416,8 @@ bt_status_t HeadsetInterface::PhoneStateChange(int num_active, int num_held,
{
std::string cell_number(number);
BTM_LogHistory(kBtmLogTag, raw_address, "Call Incoming",
- base::StringPrintf("number:%s", PRIVATE_CELL(cell_number)));
+ std::format("number:{}", PRIVATE_CELL(cell_number)));
}
- // base::StringPrintf("number:%s", PRIVATE_CELL(number)));
break;
case BTHF_CALL_STATE_DIALING:
if (!(num_active + num_held) && is_active_device(*bd_addr)) {
diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc
index 1a9855ef31..70631dbf2f 100644
--- a/system/btif/src/btif_hh.cc
+++ b/system/btif/src/btif_hh.cc
@@ -571,8 +571,9 @@ static void hh_open_handler(tBTA_HH_CONN& conn) {
dev_status = p_dev->dev_status;
}
- if (std::find(btif_hh_cb.pending_connections.begin(), btif_hh_cb.pending_connections.end(),
- conn.link_spec) != btif_hh_cb.pending_connections.end()) {
+ if (std::find(btif_hh_cb.new_connection_requests.begin(),
+ btif_hh_cb.new_connection_requests.end(),
+ conn.link_spec) != btif_hh_cb.new_connection_requests.end()) {
log::verbose("Device connection was pending for: {}, status: {}", conn.link_spec,
btif_hh_status_text(btif_hh_cb.status));
dev_status = BTHH_CONN_STATE_CONNECTING;
@@ -602,7 +603,7 @@ static void hh_open_handler(tBTA_HH_CONN& conn) {
BTHH_STATE_UPDATE(conn.link_spec, BTHH_CONN_STATE_CONNECTING);
}
- btif_hh_cb.pending_connections.remove(conn.link_spec);
+ btif_hh_cb.new_connection_requests.remove(conn.link_spec);
if (conn.status != BTA_HH_OK) {
btif_dm_hh_open_failed(&conn.link_spec.addrt.bda);
@@ -1036,7 +1037,7 @@ bt_status_t btif_hh_virtual_unplug(const tAclLinkSpec& link_spec) {
if (btif_hh_find_dev_by_link_spec(link_spec) != nullptr ||
btif_hh_find_added_dev(link_spec) != nullptr) {
// Remove pending connection if address matches
- btif_hh_cb.pending_connections.remove_if(
+ btif_hh_cb.new_connection_requests.remove_if(
[link_spec](auto ls) { return ls.addrt.bda == link_spec.addrt.bda; });
btif_hh_remove_device(link_spec);
@@ -1047,7 +1048,7 @@ bt_status_t btif_hh_virtual_unplug(const tAclLinkSpec& link_spec) {
// Abort outgoing initial connection attempt
bool pending_connection = false;
- for (auto ls : btif_hh_cb.pending_connections) {
+ for (auto ls : btif_hh_cb.new_connection_requests) {
if (ls.addrt.bda == link_spec.addrt.bda) {
pending_connection = true;
break;
@@ -1055,7 +1056,7 @@ bt_status_t btif_hh_virtual_unplug(const tAclLinkSpec& link_spec) {
}
if (pending_connection) {
- btif_hh_cb.pending_connections.remove_if(
+ btif_hh_cb.new_connection_requests.remove_if(
[link_spec](auto ls) { return ls.addrt.bda == link_spec.addrt.bda; });
/* need to notify up-layer device is disconnected to avoid
@@ -1120,11 +1121,16 @@ bt_status_t btif_hh_connect(const tAclLinkSpec& link_spec) {
p_dev->dev_status = BTHH_CONN_STATE_CONNECTING;
}
+ // Add the new connection to the pending list
+ if (!com::android::bluetooth::flags::pending_hid_connection_cancellation() ||
+ added_dev == nullptr) {
+ btif_hh_cb.new_connection_requests.push_back(link_spec);
+ }
+
/* Not checking the NORMALLY_Connectible flags from sdp record, and anyways
sending this request from host, for subsequent user initiated connection.
If the remote is not in pagescan mode, we will do 2 retries to connect before
giving up */
- btif_hh_cb.pending_connections.push_back(link_spec);
BTA_HhOpen(link_spec);
do_in_jni_thread(base::Bind(
@@ -1580,7 +1586,7 @@ static bt_status_t connect(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type, tBT_TR
BTHH_LOG_LINK(link_spec);
if (!com::android::bluetooth::flags::initiate_multiple_hid_connections() &&
- !btif_hh_cb.pending_connections.empty()) {
+ !btif_hh_cb.new_connection_requests.empty()) {
log::warn("HH status = {}", btif_hh_status_text(btif_hh_cb.status));
return BT_STATUS_BUSY;
} else if (btif_hh_cb.status == BTIF_HH_DISABLED || btif_hh_cb.status == BTIF_HH_DISABLING) {
@@ -1645,12 +1651,16 @@ static bt_status_t disconnect(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type,
log::warn("Device {} already not connected, state: {}", p_dev->link_spec,
bthh_connection_state_text(p_dev->dev_status));
p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+
+ if (com::android::bluetooth::flags::pending_hid_connection_cancellation()) {
+ btif_hh_cb.new_connection_requests.remove(link_spec);
+ }
return BT_STATUS_DONE;
} else if (com::android::bluetooth::flags::initiate_multiple_hid_connections() &&
- std::find(btif_hh_cb.pending_connections.begin(),
- btif_hh_cb.pending_connections.end(),
- link_spec) != btif_hh_cb.pending_connections.end()) {
- btif_hh_cb.pending_connections.remove(link_spec);
+ std::find(btif_hh_cb.new_connection_requests.begin(),
+ btif_hh_cb.new_connection_requests.end(),
+ link_spec) != btif_hh_cb.new_connection_requests.end()) {
+ btif_hh_cb.new_connection_requests.remove(link_spec);
log::info("Pending connection cancelled {}", link_spec);
return BT_STATUS_SUCCESS;
}
@@ -1688,7 +1698,7 @@ static bt_status_t virtual_unplug(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type,
btif_hh_device_t* p_dev = btif_hh_find_dev_by_link_spec(link_spec);
if (com::android::bluetooth::flags::remove_input_device_on_vup()) {
bool pending_connection = false;
- for (auto ls : btif_hh_cb.pending_connections) {
+ for (auto ls : btif_hh_cb.new_connection_requests) {
if (ls.addrt.bda == link_spec.addrt.bda) {
pending_connection = true;
break;
@@ -2098,7 +2108,7 @@ static void cleanup(void) {
btif_hh_cb.service_dereg_active = FALSE;
btif_disable_service(BTA_HID_SERVICE_ID);
}
- btif_hh_cb.pending_connections.clear();
+ btif_hh_cb.new_connection_requests.clear();
for (i = 0; i < BTIF_HH_MAX_HID; i++) {
p_dev = &btif_hh_cb.devices[i];
int fd = (com::android::bluetooth::flags::hid_report_queuing() ? p_dev->internal_send_fd
@@ -2184,7 +2194,7 @@ void DumpsysHid(int fd) {
LOG_DUMPSYS(fd, "status:%s num_devices:%u", btif_hh_status_text(btif_hh_cb.status).c_str(),
btif_hh_cb.device_num);
LOG_DUMPSYS(fd, "status:%s", btif_hh_status_text(btif_hh_cb.status).c_str());
- for (auto link_spec : btif_hh_cb.pending_connections) {
+ for (auto link_spec : btif_hh_cb.new_connection_requests) {
LOG_DUMPSYS(fd, "Pending connection: %s", link_spec.ToRedactedStringForLogging().c_str());
}
for (unsigned i = 0; i < BTIF_HH_MAX_HID; i++) {
diff --git a/system/btif/src/btif_rc.cc b/system/btif/src/btif_rc.cc
index 5b97f454b6..72c4bdd690 100644
--- a/system/btif/src/btif_rc.cc
+++ b/system/btif/src/btif_rc.cc
@@ -5544,7 +5544,7 @@ void btif_debug_rc_dump(int fd) {
for (int i = 0; i < BTIF_RC_NUM_CONN; ++i) {
btif_rc_device_cb_t* p_dev = &btif_rc_cb.rc_multi_cb[i];
if (p_dev->rc_state != BTRC_CONNECTION_STATE_DISCONNECTED) {
- dprintf(fd, " %s:\n", ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr));
+ dprintf(fd, " %s:\n", p_dev->rc_addr.ToRedactedStringForLogging().c_str());
rc_transaction_set_t* transaction_set = &(p_dev->transaction_set);
std::unique_lock<std::recursive_mutex> lock(transaction_set->label_lock);
diff --git a/system/btif/src/btif_sock.cc b/system/btif/src/btif_sock.cc
index 04b43dda0e..d58326e571 100644
--- a/system/btif/src/btif_sock.cc
+++ b/system/btif/src/btif_sock.cc
@@ -22,12 +22,14 @@
#include <base/functional/callback.h>
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
#include <atomic>
#include "bta/include/bta_api.h"
+#include "btif_sock_hal.h"
#include "btif_sock_l2cap.h"
#include "btif_sock_logging.h"
#include "btif_sock_rfc.h"
@@ -43,9 +45,13 @@ using bluetooth::Uuid;
using namespace bluetooth;
static bt_status_t btsock_listen(btsock_type_t type, const char* service_name, const Uuid* uuid,
- int channel, int* sock_fd, int flags, int app_uid);
+ int channel, int* sock_fd, int flags, int app_uid,
+ btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size);
static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type, const Uuid* uuid,
- int channel, int* sock_fd, int flags, int app_uid);
+ int channel, int* sock_fd, int flags, int app_uid,
+ btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size);
static void btsock_request_max_tx_data_length(const RawAddress& bd_addr);
static bt_status_t btsock_control_req(uint8_t dlci, const RawAddress& bd_addr, uint8_t modem_signal,
uint8_t break_signal, uint8_t discard_buffers,
@@ -112,6 +118,13 @@ bt_status_t btif_sock_init(uid_set_t* uid_set) {
goto error;
}
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ status = btsock_hal_init();
+ if (status != BT_STATUS_SUCCESS) {
+ log::warn("error initializing socket hal: {}", status);
+ }
+ }
+
return BT_STATUS_SUCCESS;
error:
@@ -148,7 +161,8 @@ static bt_status_t btsock_control_req(uint8_t dlci, const RawAddress& bd_addr, u
static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
const Uuid* service_uuid, int channel, int* sock_fd, int flags,
- int app_uid) {
+ int app_uid, btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size) {
if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
log::assert_that(sock_fd != NULL, "assert failed: sock_fd != NULL");
}
@@ -158,20 +172,25 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
log::info(
"Attempting listen for socket connections for device: {}, type: {}, "
- "channel: {}, app_uid: {}",
- RawAddress::kEmpty, type, channel, app_uid);
+ "channel: {}, app_uid: {}, data_path: {}, hub_id: {}, endpoint_id: {}, "
+ "max_rx_packet_size: {}",
+ RawAddress::kEmpty, type, channel, app_uid, data_path, hub_id, endpoint_id,
+ max_rx_packet_size);
btif_sock_connection_logger(RawAddress::kEmpty, 0, type, SOCKET_CONNECTION_STATE_LISTENING,
SOCKET_ROLE_LISTEN, app_uid, channel, 0, 0, service_name);
switch (type) {
case BTSOCK_RFCOMM:
- status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd, flags, app_uid);
+ status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd, flags, app_uid,
+ data_path, socket_name, hub_id, endpoint_id, max_rx_packet_size);
break;
case BTSOCK_L2CAP:
- status = btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
+ status = btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid, data_path,
+ socket_name, hub_id, endpoint_id, max_rx_packet_size);
break;
case BTSOCK_L2CAP_LE:
status = btsock_l2cap_listen(service_name, channel, sock_fd, flags | BTSOCK_FLAG_LE_COC,
- app_uid);
+ app_uid, data_path, socket_name, hub_id, endpoint_id,
+ max_rx_packet_size);
break;
case BTSOCK_SCO:
status = btsock_sco_listen(sock_fd, flags);
@@ -194,14 +213,16 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
}
static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type, const Uuid* uuid,
- int channel, int* sock_fd, int flags, int app_uid) {
+ int channel, int* sock_fd, int flags, int app_uid,
+ btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size) {
log::assert_that(bd_addr != NULL, "assert failed: bd_addr != NULL");
log::assert_that(sock_fd != NULL, "assert failed: sock_fd != NULL");
log::info(
"Attempting socket connection for device: {}, type: {}, channel: {}, "
- "app_uid: {}",
- *bd_addr, type, channel, app_uid);
+ "app_uid: {}, data_path: {}, hub_id: {}, endpoint_id: {}, max_rx_packet_size: {}",
+ *bd_addr, type, channel, app_uid, data_path, hub_id, endpoint_id, max_rx_packet_size);
*sock_fd = INVALID_FD;
bt_status_t status = BT_STATUS_SOCKET_ERROR;
@@ -211,15 +232,18 @@ static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
uuid ? uuid->ToString().c_str() : "");
switch (type) {
case BTSOCK_RFCOMM:
- status = btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags, app_uid);
+ status = btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags, app_uid, data_path,
+ socket_name, hub_id, endpoint_id, max_rx_packet_size);
break;
case BTSOCK_L2CAP:
- status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
+ status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid, data_path,
+ socket_name, hub_id, endpoint_id, max_rx_packet_size);
break;
case BTSOCK_L2CAP_LE:
- status = btsock_l2cap_connect(bd_addr, channel, sock_fd, (flags | BTSOCK_FLAG_LE_COC),
- app_uid);
+ status =
+ btsock_l2cap_connect(bd_addr, channel, sock_fd, (flags | BTSOCK_FLAG_LE_COC), app_uid,
+ data_path, socket_name, hub_id, endpoint_id, max_rx_packet_size);
break;
case BTSOCK_SCO:
status = btsock_sco_connect(bd_addr, sock_fd, flags);
diff --git a/system/btif/src/btif_sock_hal.cc b/system/btif/src/btif_sock_hal.cc
new file mode 100644
index 0000000000..ce820833d0
--- /dev/null
+++ b/system/btif/src/btif_sock_hal.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bt_btif_sock_hal"
+
+#include "btif/include/btif_sock_hal.h"
+
+#include "btif/include/btif_sock_l2cap.h"
+#include "btif/include/btif_sock_rfc.h"
+#include "lpp/lpp_offload_interface.h"
+#include "main/shim/entry.h"
+#include "stack/include/main_thread.h"
+
+using namespace bluetooth;
+
+class BtifSocketHalCallback : public hal::SocketHalCallback {
+public:
+ void SocketOpenedComplete(uint64_t socket_id, hal::SocketStatus status) const override {
+ log::info("socket_id: {}, status: {}", socket_id, static_cast<int>(status));
+ if (btsock_l2cap_in_use(socket_id)) {
+ do_in_main_thread(base::BindOnce(on_btsocket_l2cap_opened_complete, socket_id,
+ (status == hal::SocketStatus::SUCCESS)));
+ } else if (btsock_rfc_in_use(socket_id)) {
+ do_in_main_thread(base::BindOnce(on_btsocket_rfc_opened_complete, socket_id,
+ (status == hal::SocketStatus::SUCCESS)));
+ } else {
+ log::error("Unable to find socket with socket_id:{}", socket_id);
+ }
+ }
+
+ void SocketClose(uint64_t socket_id) const override {
+ log::info("socket_id: {}", socket_id);
+ if (btsock_l2cap_in_use(socket_id)) {
+ do_in_main_thread(base::BindOnce(on_btsocket_l2cap_close, socket_id));
+ } else if (btsock_rfc_in_use(socket_id)) {
+ do_in_main_thread(base::BindOnce(on_btsocket_rfc_close, socket_id));
+ } else {
+ log::error("Unable to find socket with socket_id:{}", socket_id);
+ }
+ }
+};
+
+static BtifSocketHalCallback btif_socket_hal_cb;
+
+bt_status_t btsock_hal_init() {
+ log::info("");
+ auto lpp_offload_manager_interface = bluetooth::shim::GetLppOffloadManager();
+ if (lpp_offload_manager_interface == nullptr) {
+ log::warn("GetLppOffloadManager() returned nullptr!");
+ return BT_STATUS_FAIL;
+ }
+ if (!lpp_offload_manager_interface->RegisterSocketHalCallback(&btif_socket_hal_cb)) {
+ log::warn("RegisterSocketHalCallback() failed!");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
diff --git a/system/btif/src/btif_sock_l2cap.cc b/system/btif/src/btif_sock_l2cap.cc
index 3aa7162b78..2a8e4e4f9a 100644
--- a/system/btif/src/btif_sock_l2cap.cc
+++ b/system/btif/src/btif_sock_l2cap.cc
@@ -16,11 +16,11 @@
*/
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
-#include <com_android_bluetooth_flags.h>
#include <cstdint>
#include <cstring>
@@ -36,6 +36,8 @@
#include "gd/os/rand.h"
#include "include/hardware/bluetooth.h"
#include "internal_include/bt_target.h"
+#include "lpp/lpp_offload_interface.h"
+#include "main/shim/entry.h"
#include "osi/include/allocator.h"
#include "osi/include/osi.h"
#include "stack/include/bt_hdr.h"
@@ -65,6 +67,7 @@ typedef struct l2cap_socket {
int channel; // PSM
int our_fd; // fd from our side
int app_fd; // fd from app's side
+ int listen_fd; // listen socket fd from our side
unsigned bytes_buffered;
struct packet* first_packet; // fist packet to be delivered to app
@@ -84,9 +87,18 @@ typedef struct l2cap_socket {
uint16_t local_cid; // The local CID
uint16_t remote_cid; // The remote CID
Uuid conn_uuid; // The connection uuid
+ uint64_t socket_id; // Socket ID in connected state
+ btsock_data_path_t data_path; // socket data path
+ char socket_name[128]; // descriptive socket name
+ uint64_t hub_id; // ID of the hub to which the end point belongs
+ uint64_t endpoint_id; // ID of the hub end point
+ bool is_accepting; // is app accepting on server socket?
} l2cap_socket;
static void btsock_l2cap_server_listen(l2cap_socket* sock);
+static uint64_t btif_l2cap_sock_generate_socket_id();
+static void on_cl_l2cap_psm_connect_offload_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock);
+static void on_srv_l2cap_psm_connect_offload_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock);
static std::mutex state_lock;
@@ -98,18 +110,13 @@ static int pth = -1;
static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t l2cap_socket_id);
/* TODO: Consider to remove this buffer, as we have a buffer in l2cap as well,
- * and we risk
- * a buffer overflow with this implementation if the socket data is not
- * read from
- * JAVA for a while. In such a case we should use flow control to tell the
- * sender to
- * back off.
- * BUT remember we need to avoid blocking the BTA task execution - hence
- * we cannot
- * directly write to the socket.
- * we should be able to change to store the data pointer here, and just
- * wait
- * confirming the l2cap_ind until we have more space in the buffer. */
+ * and we risk a buffer overflow with this implementation if the socket data is not
+ * read from JAVA for a while. In such a case we should use flow control to tell the
+ * sender to back off.
+ * BUT remember we need to avoid blocking the BTA task execution - hence
+ * we cannot directly write to the socket. We should be able to change to store the
+ * data pointer here, and just wait confirming the l2cap_ind until we have more space
+ * in the buffer. */
/* returns false if none - caller must free "data" memory when done with it */
static char packet_get_head_l(l2cap_socket* sock, uint8_t** data, uint32_t* len) {
@@ -246,13 +253,19 @@ static void btsock_l2cap_free_l(l2cap_socket* sock) {
log::info(
"Disconnected L2CAP connection for device: {}, channel: {}, app_uid: {}, "
- "id: {}, is_le: {}",
- sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc);
+ "id: {}, is_le: {}, socket_id: {}",
+ sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc, sock->socket_id);
btif_sock_connection_logger(
sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
SOCKET_CONNECTION_STATE_DISCONNECTED,
sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->app_uid, sock->channel,
sock->tx_bytes, sock->rx_bytes, sock->name);
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (sock->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD && !sock->server &&
+ sock->socket_id != 0) {
+ bluetooth::shim::GetLppOffloadManager()->SocketClosed(sock->socket_id);
+ }
+ }
if (sock->next) {
sock->next->prev = sock->prev;
}
@@ -321,10 +334,10 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name, const RawAddress* ad
}
#if TARGET_FLOSS
- //Changed socket type to SOCK_STREAM to address a platform issue on FLOSS.
- //This is a workaround and not the recommended approach.
- //SOCK_SEQPACKET is preferred for L2CAP LE CoC channels because it preserves L2CAP
- //packet boundaries, ensuring message integrity.
+ // Changed socket type to SOCK_STREAM to address a platform issue on FLOSS.
+ // This is a workaround and not the recommended approach.
+ // SOCK_SEQPACKET is preferred for L2CAP LE CoC channels because it preserves L2CAP
+ // packet boundaries, ensuring message integrity.
sock_type = SOCK_STREAM;
#endif
if (socketpair(AF_LOCAL, sock_type, 0, fds)) {
@@ -334,12 +347,19 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name, const RawAddress* ad
sock->our_fd = fds[0];
sock->app_fd = fds[1];
+ sock->listen_fd = -1;
sock->security = security;
sock->server = is_server;
sock->connected = false;
sock->handle = 0;
sock->server_psm_sent = false;
sock->app_uid = -1;
+ sock->conn_uuid = Uuid::kEmpty;
+ sock->socket_id = 0;
+ sock->data_path = BTSOCK_DATA_PATH_NO_OFFLOAD;
+ sock->hub_id = 0;
+ sock->endpoint_id = 0;
+ sock->is_accepting = false;
if (name) {
strncpy(sock->name, name, sizeof(sock->name) - 1);
@@ -370,7 +390,7 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name, const RawAddress* ad
while (t && t->id != sock->id) {
t = t->next;
}
- if (!t && sock->id) { /* non-zeor handle is unique -> we're done */
+ if (!t && sock->id) { /* non-zero handle is unique -> we're done */
break;
}
/* if we're here, we found a duplicate */
@@ -446,7 +466,7 @@ static uint64_t uuid_msb(const Uuid& uuid) {
static bool send_app_connect_signal(int fd, const RawAddress* addr, int channel, int status,
int send_fd, uint16_t rx_mtu, uint16_t tx_mtu,
- const Uuid& conn_uuid) {
+ const Uuid& conn_uuid, uint64_t socket_id) {
sock_connect_signal_t cs;
cs.size = sizeof(cs);
cs.bd_addr = *addr;
@@ -456,6 +476,7 @@ static bool send_app_connect_signal(int fd, const RawAddress* addr, int channel,
cs.max_tx_packet_size = tx_mtu;
cs.conn_uuid_lsb = uuid_lsb(conn_uuid);
cs.conn_uuid_msb = uuid_msb(conn_uuid);
+ cs.socket_id = socket_id;
if (send_fd != -1) {
if (sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs)) {
return true;
@@ -531,7 +552,7 @@ static void on_cl_l2cap_init(tBTA_JV_L2CAP_CL_INIT* p_init, uint32_t id) {
* will be a clone of the sock representing the BluetoothServerSocket.
* */
static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock) {
- // std::mutex locked by caller
+ // state_lock taken by caller
l2cap_socket* accept_rs = btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
accept_rs->connected = true;
accept_rs->security = sock->security;
@@ -541,10 +562,22 @@ static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket*
sock->handle = -1; /* We should no longer associate this handle with the server socket */
accept_rs->is_le_coc = sock->is_le_coc;
accept_rs->tx_mtu = sock->tx_mtu = p_open->tx_mtu;
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349374
+ accept_rs->rx_mtu = sock->rx_mtu;
+ }
accept_rs->local_cid = p_open->local_cid;
accept_rs->remote_cid = p_open->remote_cid;
+ // TODO(b/342012881) Remove connection uuid when offload socket API is landed.
Uuid uuid = Uuid::From128BitBE(bluetooth::os::GenerateRandom<Uuid::kNumBytes128>());
accept_rs->conn_uuid = uuid;
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349374
+ accept_rs->socket_id = btif_l2cap_sock_generate_socket_id();
+ accept_rs->data_path = sock->data_path;
+ strncpy(accept_rs->socket_name, sock->socket_name, sizeof(accept_rs->socket_name) - 1);
+ accept_rs->socket_name[sizeof(accept_rs->socket_name) - 1] = '\0';
+ accept_rs->hub_id = sock->hub_id;
+ accept_rs->endpoint_id = sock->endpoint_id;
+ }
/* Swap IDs to hand over the GAP connection to the accepted socket, and start
a new server on the newly create socket ID. */
@@ -554,8 +587,9 @@ static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket*
log::info(
"Connected to L2CAP connection for device: {}, channel: {}, app_uid: {}, "
- "id: {}, is_le: {}",
- sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc);
+ "id: {}, is_le: {}, socket_id: {}, rx_mtu: {}",
+ sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc, accept_rs->socket_id,
+ accept_rs->rx_mtu);
btif_sock_connection_logger(accept_rs->addr, accept_rs->id,
accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
SOCKET_CONNECTION_STATE_CONNECTED,
@@ -566,11 +600,15 @@ static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket*
btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION, sock->id);
btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, accept_rs->id);
send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0, accept_rs->app_fd,
- sock->rx_mtu, p_open->tx_mtu, accept_rs->conn_uuid);
+ sock->rx_mtu, p_open->tx_mtu, accept_rs->conn_uuid, accept_rs->socket_id);
accept_rs->app_fd = -1; // The fd is closed after sent to app in send_app_connect_signal()
// But for some reason we still leak a FD - either the server socket
// one or the accept socket one.
btsock_l2cap_server_listen(sock);
+ // start monitoring the socketpair to get call back when app is accepting on server socket
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349375
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+ }
}
static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock) {
@@ -578,8 +616,12 @@ static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket*
sock->tx_mtu = p_open->tx_mtu;
sock->local_cid = p_open->local_cid;
sock->remote_cid = p_open->remote_cid;
+ // TODO(b/342012881) Remove connection uuid when offload socket API is landed.
Uuid uuid = Uuid::From128BitBE(bluetooth::os::GenerateRandom<Uuid::kNumBytes128>());
sock->conn_uuid = uuid;
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349374
+ sock->socket_id = btif_l2cap_sock_generate_socket_id();
+ }
if (!send_app_psm_or_chan_l(sock)) {
log::error("Unable to send l2cap socket to application socket_id:{}", sock->id);
@@ -587,15 +629,16 @@ static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket*
}
if (!send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1, sock->rx_mtu,
- p_open->tx_mtu, sock->conn_uuid)) {
+ p_open->tx_mtu, sock->conn_uuid, sock->socket_id)) {
log::error("Unable to connect l2cap socket to application socket_id:{}", sock->id);
return;
}
log::info(
"Connected to L2CAP connection for device: {}, channel: {}, app_uid: {}, "
- "id: {}, is_le: {}",
- sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc);
+ "id: {}, is_le: {}, socket_id: {}, rx_mtu: {}",
+ sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc, sock->socket_id,
+ sock->rx_mtu);
btif_sock_connection_logger(sock->addr, sock->id,
sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
SOCKET_CONNECTION_STATE_CONNECTED,
@@ -621,10 +664,19 @@ static void on_l2cap_connect(tBTA_JV* p_data, uint32_t id) {
sock->tx_mtu = le_open->tx_mtu;
if (psm_open->status == tBTA_JV_STATUS::SUCCESS) {
- if (!sock->server) {
- on_cl_l2cap_psm_connect_l(psm_open, sock);
+ if (!com::android::bluetooth::flags::socket_settings_api() || // Added with aosp/3349378
+ sock->data_path == BTSOCK_DATA_PATH_NO_OFFLOAD) {
+ if (!sock->server) {
+ on_cl_l2cap_psm_connect_l(psm_open, sock);
+ } else {
+ on_srv_l2cap_psm_connect_l(psm_open, sock);
+ }
} else {
- on_srv_l2cap_psm_connect_l(psm_open, sock);
+ if (!sock->server) {
+ on_cl_l2cap_psm_connect_offload_l(psm_open, sock);
+ } else {
+ on_srv_l2cap_psm_connect_offload_l(psm_open, sock);
+ }
}
} else {
log::error("Unable to open socket after receiving connection socket_id:{}", sock->id);
@@ -825,6 +877,15 @@ static void btsock_l2cap_server_listen(l2cap_socket* sock) {
/* Setup ETM settings: mtu will be set below */
std::unique_ptr<tL2CAP_CFG_INFO> cfg = std::make_unique<tL2CAP_CFG_INFO>(
tL2CAP_CFG_INFO{.fcr_present = true, .fcr = kDefaultErtmOptions});
+ /* For hardware offload data path, host stack sets the initial credits to 0. The offload stack
+ * should send initial credits to peer device through L2CAP signaling command when the data path
+ * is switched successfully. */
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349376
+ if (sock->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ cfg->init_credit_present = true;
+ cfg->init_credit = 0;
+ }
+ }
std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info;
if (!sock->is_le_coc) {
@@ -835,9 +896,38 @@ static void btsock_l2cap_server_listen(l2cap_socket* sock) {
sock->rx_mtu, std::move(cfg), btsock_l2cap_cbk, sock->id);
}
+/*
+ * Determine the local MTU for the offloaded L2CAP connection.
+ *
+ * The local MTU is selected as the minimum of:
+ * - The socket hal's offload capabilities (socket_cap.leCocCapabilities.mtu)
+ * - The application's requested maximum RX packet size (app_max_rx_packet_size)
+ *
+ * However, the MTU must be at least the minimum required by the L2CAP LE
+ * specification (L2CAP_SDU_LENGTH_LE_MIN).
+ */
+
+static bool btsock_l2cap_get_offload_mtu(uint16_t* rx_mtu, uint16_t app_max_rx_packet_size) {
+ hal::SocketCapabilities socket_cap =
+ bluetooth::shim::GetLppOffloadManager()->GetSocketCapabilities();
+ if (!socket_cap.le_coc_capabilities.number_of_supported_sockets) {
+ return false;
+ }
+ /* Socket HAL client has already verified that the MTU is in a valid range. */
+ uint16_t mtu = static_cast<uint16_t>(socket_cap.le_coc_capabilities.mtu);
+ mtu = std::min(mtu, app_max_rx_packet_size);
+ if (mtu < L2CAP_SDU_LENGTH_LE_MIN) {
+ mtu = L2CAP_SDU_LENGTH_LE_MIN;
+ }
+ *rx_mtu = mtu;
+ return true;
+}
+
static bt_status_t btsock_l2cap_listen_or_connect(const char* name, const RawAddress* addr,
int channel, int* sock_fd, int flags, char listen,
- int app_uid) {
+ int app_uid, btsock_data_path_t data_path,
+ const char* socket_name, uint64_t hub_id,
+ uint64_t endpoint_id, int max_rx_packet_size) {
if (!is_inited()) {
return BT_STATUS_NOT_READY;
}
@@ -875,11 +965,31 @@ static bt_status_t btsock_l2cap_listen_or_connect(const char* name, const RawAdd
sock->channel = channel;
sock->app_uid = app_uid;
sock->is_le_coc = is_le_coc;
- sock->rx_mtu = is_le_coc ? L2CAP_SDU_LENGTH_LE_MAX : L2CAP_SDU_LENGTH_MAX;
+ if (com::android::bluetooth::flags::socket_settings_api() && // Added with aosp/3349377
+ data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ if (!btsock_l2cap_get_offload_mtu(&sock->rx_mtu, static_cast<uint16_t>(max_rx_packet_size))) {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ } else {
+ sock->rx_mtu = is_le_coc ? L2CAP_SDU_LENGTH_LE_MAX : L2CAP_SDU_LENGTH_MAX;
+ }
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349374
+ sock->data_path = data_path;
+ if (socket_name) {
+ strncpy(sock->socket_name, socket_name, sizeof(sock->socket_name) - 1);
+ sock->socket_name[sizeof(sock->socket_name) - 1] = '\0';
+ }
+ sock->hub_id = hub_id;
+ sock->endpoint_id = endpoint_id;
+ }
/* "role" is never initialized in rfcomm code */
if (listen) {
btsock_l2cap_server_listen(sock);
+ // start monitoring the socketpair to get call back when app is accepting on server socket
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349375
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+ }
} else {
tBTA_JV_CONN_TYPE connection_type =
sock->is_le_coc ? tBTA_JV_CONN_TYPE::L2CAP_LE : tBTA_JV_CONN_TYPE::L2CAP;
@@ -887,6 +997,15 @@ static bt_status_t btsock_l2cap_listen_or_connect(const char* name, const RawAdd
/* Setup ETM settings: mtu will be set below */
std::unique_ptr<tL2CAP_CFG_INFO> cfg = std::make_unique<tL2CAP_CFG_INFO>(
tL2CAP_CFG_INFO{.fcr_present = true, .fcr = kDefaultErtmOptions});
+ /* For hardware offload data path, host stack sets the initial credits to 0. The offload stack
+ * should send initial credits to peer device through L2CAP signaling command when the data path
+ * is switched successfully. */
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349376
+ if (sock->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ cfg->init_credit_present = true;
+ cfg->init_credit = 0;
+ }
+ }
std::unique_ptr<tL2CAP_ERTM_INFO> ertm_info;
if (!sock->is_le_coc) {
@@ -909,14 +1028,19 @@ static bt_status_t btsock_l2cap_listen_or_connect(const char* name, const RawAdd
return BT_STATUS_SUCCESS;
}
-bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd, int flags,
- int app_uid) {
- return btsock_l2cap_listen_or_connect(name, NULL, channel, sock_fd, flags, 1, app_uid);
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd, int flags, int app_uid,
+ btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size) {
+ return btsock_l2cap_listen_or_connect(name, NULL, channel, sock_fd, flags, 1, app_uid, data_path,
+ socket_name, hub_id, endpoint_id, max_rx_packet_size);
}
bt_status_t btsock_l2cap_connect(const RawAddress* bd_addr, int channel, int* sock_fd, int flags,
- int app_uid) {
- return btsock_l2cap_listen_or_connect(NULL, bd_addr, channel, sock_fd, flags, 0, app_uid);
+ int app_uid, btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size) {
+ return btsock_l2cap_listen_or_connect(NULL, bd_addr, channel, sock_fd, flags, 0, app_uid,
+ data_path, socket_name, hub_id, endpoint_id,
+ max_rx_packet_size);
}
/* return true if we have more to send and should wait for user readiness, false
@@ -962,7 +1086,111 @@ inline uint8_t* get_l2cap_sdu_start_ptr(BT_HDR* msg) {
return (uint8_t*)(msg) + BT_HDR_SIZE + msg->offset;
}
+// state_lock taken by caller
+bool btsock_l2cap_read_signaled_on_connected_socket(int fd, int flags, uint32_t user_id,
+ l2cap_socket* sock) {
+ if (!sock->connected) {
+ return false;
+ }
+ int size = 0;
+ bool ioctl_success = ioctl(sock->our_fd, FIONREAD, &size) == 0;
+ if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl_success && size)) {
+ /* FIONREAD return number of bytes that are immediately available for
+ reading, might be bigger than awaiting packet.
+
+ BluetoothSocket.write(...) guarantees that any packet send to this
+ socket is broken into pieces no bigger than MTU bytes (as requested
+ by BT spec). */
+ size = std::min(size, (int)sock->tx_mtu);
+
+ BT_HDR* buffer = malloc_l2cap_buf(size);
+ /* The socket is created with SOCK_SEQPACKET, hence we read one message
+ * at the time. */
+ ssize_t count;
+ OSI_NO_INTR(count = recv(fd, get_l2cap_sdu_start_ptr(buffer), size,
+ MSG_NOSIGNAL | MSG_DONTWAIT | MSG_TRUNC));
+ if (count > sock->tx_mtu) {
+ /* This can't happen thanks to check in BluetoothSocket.java but leave
+ * this in case this socket is ever used anywhere else*/
+ log::error("recv more than MTU. Data will be lost: {}", count);
+ count = sock->tx_mtu;
+ }
+
+ /* When multiple packets smaller than MTU are flushed to the socket, the
+ size of the single packet read could be smaller than the ioctl
+ reported total size of awaiting packets. Hence, we adjust the buffer
+ length. */
+ buffer->len = count;
+
+ // will take care of freeing buffer
+ BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, user_id);
+ }
+ return true;
+}
+
+// state_lock taken by caller
+bool btsock_l2cap_read_signaled_on_listen_socket(int fd, int /* flags */, uint32_t /* user_id */,
+ l2cap_socket* sock) {
+ int size = 0;
+ bool ioctl_success = ioctl(sock->our_fd, FIONREAD, &size) == 0;
+ if (ioctl_success && size) {
+ sock_accept_signal_t accept_signal = {};
+ ssize_t count;
+ OSI_NO_INTR(count = recv(fd, reinterpret_cast<uint8_t*>(&accept_signal), sizeof(accept_signal),
+ MSG_NOSIGNAL | MSG_DONTWAIT | MSG_TRUNC));
+ if (count != sizeof(accept_signal) || count != accept_signal.size) {
+ log::error("Unexpected count: {}, sizeof(accept_signal): {}, accept_signal.size: {}", count,
+ sizeof(accept_signal), accept_signal.size);
+ return false;
+ }
+ sock->is_accepting = accept_signal.is_accepting;
+ log::info("Server socket: {}, is_accepting: {}", sock->id, sock->is_accepting);
+ }
+ return true;
+}
+
+void btsock_l2cap_signaled_flagged(int fd, int flags, uint32_t user_id) {
+ char drop_it = false;
+
+ /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
+ * hold the lock. */
+ std::unique_lock<std::mutex> lock(state_lock);
+ l2cap_socket* sock = btsock_l2cap_find_by_id_l(user_id);
+ if (!sock) {
+ return;
+ }
+ if (flags & SOCK_THREAD_FD_RD) {
+ if (!sock->server) {
+ // app sending data on connection socket
+ if (!btsock_l2cap_read_signaled_on_connected_socket(fd, flags, user_id, sock)) {
+ drop_it = true;
+ }
+ } else {
+ // app sending signal on listen socket
+ if (!btsock_l2cap_read_signaled_on_listen_socket(fd, flags, user_id, sock)) {
+ drop_it = true;
+ }
+ }
+ }
+ if (flags & SOCK_THREAD_FD_WR) {
+ // app is ready to receive more data, tell stack to enable the data flow
+ if (flush_incoming_que_on_wr_signal_l(sock) && sock->connected) {
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR, sock->id);
+ }
+ }
+ if (drop_it || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+ int size = 0;
+ if (drop_it || ioctl(sock->our_fd, FIONREAD, &size) != 0 || size == 0) {
+ btsock_l2cap_free_l(sock);
+ }
+ }
+}
+
void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349375
+ btsock_l2cap_signaled_flagged(fd, flags, user_id);
+ return;
+ }
char drop_it = false;
/* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
@@ -1074,3 +1302,203 @@ bt_status_t btsock_l2cap_get_l2cap_remote_cid(Uuid& conn_uuid, uint16_t* cid) {
*cid = sock->remote_cid;
return BT_STATUS_SUCCESS;
}
+
+// TODO(b/380189525): Replace the randomized socket ID with static counter when we don't have
+// security concerns about using static counter.
+static uint64_t btif_l2cap_sock_generate_socket_id() {
+ uint64_t socket_id;
+ do {
+ socket_id = bluetooth::os::GenerateRandomUint64();
+ } while (!socket_id);
+ return socket_id;
+}
+
+/* only call with state_lock taken */
+static l2cap_socket* btsock_l2cap_find_by_socket_id_l(uint64_t socket_id) {
+ l2cap_socket* sock = socks;
+
+ while (sock) {
+ if (sock->socket_id == socket_id) {
+ return sock;
+ }
+ sock = sock->next;
+ }
+
+ return nullptr;
+}
+
+bool btsock_l2cap_in_use(uint64_t socket_id) {
+ std::unique_lock<std::mutex> lock(state_lock);
+ return btsock_l2cap_find_by_socket_id_l(socket_id) != nullptr;
+}
+
+void on_btsocket_l2cap_opened_complete(uint64_t socket_id, bool success) {
+ l2cap_socket* sock;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_socket_id_l(socket_id);
+ if (!sock) {
+ log::error("Unable to find l2cap socket with socket_id:{}", socket_id);
+ return;
+ }
+ if (!success) {
+ log::error("L2CAP opened complete failed with socket_id:{}", socket_id);
+ btsock_l2cap_free_l(sock);
+ return;
+ }
+ // If the socket was accepted from listen socket, use listen_fd.
+ if (sock->listen_fd != -1) {
+ send_app_connect_signal(sock->listen_fd, &sock->addr, sock->channel, 0, sock->app_fd,
+ sock->rx_mtu, sock->tx_mtu, sock->conn_uuid, sock->socket_id);
+ // The fd is closed after sent to app in send_app_connect_signal()
+ sock->app_fd = -1;
+ } else {
+ if (!send_app_psm_or_chan_l(sock)) {
+ log::error("Unable to send l2cap socket to application socket_id:{}", sock->id);
+ return;
+ }
+ if (!send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1, sock->rx_mtu,
+ sock->tx_mtu, sock->conn_uuid, sock->socket_id)) {
+ log::error("Unable to connect l2cap socket to application socket_id:{}", sock->id);
+ return;
+ }
+
+ log::info(
+ "Connected to L2CAP connection for device: {}, channel: {}, app_uid: {}, id: {}, "
+ "is_le: {}, socket_id: {}, rx_mtu: {}",
+ sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc, sock->socket_id,
+ sock->rx_mtu);
+ btif_sock_connection_logger(sock->addr, sock->id,
+ sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ sock->app_uid, sock->channel, 0, 0, sock->name);
+
+ log::info("Connected l2cap socket socket_id:{}", sock->id);
+ sock->connected = true;
+ }
+}
+
+void on_btsocket_l2cap_close(uint64_t socket_id) {
+ l2cap_socket* sock;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_socket_id_l(socket_id);
+ if (!sock) {
+ log::error("Unable to find l2cap socket with socket_id:{}", socket_id);
+ return;
+ }
+ log::info("L2CAP close request for socket_id:{}", socket_id);
+ btsock_l2cap_free_l(sock);
+}
+
+static void on_cl_l2cap_psm_connect_offload_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock) {
+ sock->addr = p_open->rem_bda;
+ sock->tx_mtu = p_open->tx_mtu;
+ sock->local_cid = p_open->local_cid;
+ sock->remote_cid = p_open->remote_cid;
+ // TODO(b/342012881) Remove connection uuid when offload socket API is landed.
+ Uuid uuid = Uuid::From128BitBE(bluetooth::os::GenerateRandom<Uuid::kNumBytes128>());
+ sock->conn_uuid = uuid;
+ sock->socket_id = btif_l2cap_sock_generate_socket_id();
+
+ log::info(
+ "Connected to L2CAP connection for device: {}, channel: {}, app_uid: {}, "
+ "id: {}, is_le: {}, socket_id: {}, rx_mtu: {}",
+ sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc, sock->socket_id,
+ sock->rx_mtu);
+ btif_sock_connection_logger(sock->addr, sock->id,
+ sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ sock->app_uid, sock->channel, 0, 0, sock->name);
+
+ bluetooth::hal::SocketContext socket_context = {
+ .socket_id = sock->socket_id,
+ .name = sock->socket_name,
+ .acl_connection_handle = p_open->acl_handle,
+ .channel_info = bluetooth::hal::LeCocChannelInfo(
+ p_open->local_cid, p_open->remote_cid, static_cast<uint16_t>(sock->channel),
+ sock->rx_mtu, sock->tx_mtu, p_open->local_coc_mps, p_open->remote_coc_mps,
+ p_open->local_coc_credit, p_open->remote_coc_credit),
+ .endpoint_info.hub_id = sock->hub_id,
+ .endpoint_info.endpoint_id = sock->endpoint_id,
+ };
+ if (!bluetooth::shim::GetLppOffloadManager()->SocketOpened(socket_context)) {
+ log::warn("L2CAP socket opened failed. Disconnect the incoming connection.");
+ btsock_l2cap_free_l(sock);
+ } else {
+ log::info(
+ "L2CAP socket opened successful. Will send connect signal in "
+ "on_btsocket_l2cap_opened_complete() asynchronously.");
+ }
+}
+
+static void on_srv_l2cap_psm_connect_offload_l(tBTA_JV_L2CAP_OPEN* p_open, l2cap_socket* sock) {
+ // std::mutex locked by caller
+ l2cap_socket* accept_rs = btsock_l2cap_alloc_l(sock->name, &p_open->rem_bda, false, 0);
+ accept_rs->connected = true;
+ accept_rs->security = sock->security;
+ accept_rs->channel = sock->channel;
+ accept_rs->handle = sock->handle;
+ accept_rs->app_uid = sock->app_uid;
+ sock->handle = -1; /* We should no longer associate this handle with the server socket */
+ accept_rs->is_le_coc = sock->is_le_coc;
+ accept_rs->tx_mtu = sock->tx_mtu = p_open->tx_mtu;
+ accept_rs->rx_mtu = sock->rx_mtu;
+ accept_rs->local_cid = p_open->local_cid;
+ accept_rs->remote_cid = p_open->remote_cid;
+ // TODO(b/342012881) Remove connection uuid when offload socket API is landed.
+ Uuid uuid = Uuid::From128BitBE(bluetooth::os::GenerateRandom<Uuid::kNumBytes128>());
+ accept_rs->conn_uuid = uuid;
+ accept_rs->socket_id = btif_l2cap_sock_generate_socket_id();
+ accept_rs->data_path = sock->data_path;
+ strncpy(accept_rs->socket_name, sock->socket_name, sizeof(accept_rs->socket_name) - 1);
+ accept_rs->socket_name[sizeof(accept_rs->socket_name) - 1] = '\0';
+ accept_rs->hub_id = sock->hub_id;
+ accept_rs->endpoint_id = sock->endpoint_id;
+ accept_rs->listen_fd = sock->our_fd;
+
+ /* Swap IDs to hand over the GAP connection to the accepted socket, and start
+ a new server on the newly create socket ID. */
+ uint32_t new_listen_id = accept_rs->id;
+ accept_rs->id = sock->id;
+ sock->id = new_listen_id;
+
+ log::info(
+ "Connected to L2CAP connection for device: {}, channel: {}, app_uid: {}, "
+ "id: {}, is_le: {}, socket_id: {}, rx_mtu: {}",
+ sock->addr, sock->channel, sock->app_uid, sock->id, sock->is_le_coc, accept_rs->socket_id,
+ accept_rs->rx_mtu);
+ btif_sock_connection_logger(accept_rs->addr, accept_rs->id,
+ accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ accept_rs->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ accept_rs->app_uid, accept_rs->channel, 0, 0, accept_rs->name);
+
+ bluetooth::hal::SocketContext socket_context = {
+ .socket_id = accept_rs->socket_id,
+ .name = accept_rs->socket_name,
+ .acl_connection_handle = p_open->acl_handle,
+ .channel_info = bluetooth::hal::LeCocChannelInfo(
+ p_open->local_cid, p_open->remote_cid, static_cast<uint16_t>(accept_rs->channel),
+ accept_rs->rx_mtu, accept_rs->tx_mtu, p_open->local_coc_mps,
+ p_open->remote_coc_mps, p_open->local_coc_credit, p_open->remote_coc_credit),
+ .endpoint_info.hub_id = accept_rs->hub_id,
+ .endpoint_info.endpoint_id = accept_rs->endpoint_id,
+ };
+ if (!sock->is_accepting) {
+ log::warn("Server socket is not accepting. Disconnect the incoming connection.");
+ btsock_l2cap_free_l(accept_rs);
+ } else if (!bluetooth::shim::GetLppOffloadManager()->SocketOpened(socket_context)) {
+ log::warn("L2CAP socket opened failed. Disconnect the incoming connection.");
+ btsock_l2cap_free_l(accept_rs);
+ } else {
+ log::info("L2CAP socket opened successful. Will send connect signal in async callback.");
+ }
+ // start monitor the socket
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION, sock->id);
+ btsock_l2cap_server_listen(sock);
+ // start monitoring the socketpair to get call back when app is accepting on server socket
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, sock->id);
+}
diff --git a/system/btif/src/btif_sock_logging.cc b/system/btif/src/btif_sock_logging.cc
index 9ff6980a63..338a47f2f1 100644
--- a/system/btif/src/btif_sock_logging.cc
+++ b/system/btif/src/btif_sock_logging.cc
@@ -163,7 +163,8 @@ void SockConnectionEvent::dump(const int fd) {
}
dprintf(fd, " %s\t%s\t%s \t%s \t%d \t%s\t%s\n", eventtime,
- ADDRESS_TO_LOGGABLE_CSTR(addr), str_state, str_role, channel, str_type, server_name);
+ addr.ToRedactedStringForLogging().c_str(), str_state, str_role, channel, str_type,
+ server_name);
}
static android::bluetooth::SocketConnectionstateEnum toConnectionStateEnum(int state) {
diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc
index e8bf6b42fe..de2188c5d8 100644
--- a/system/btif/src/btif_sock_rfc.cc
+++ b/system/btif/src/btif_sock_rfc.cc
@@ -36,7 +36,10 @@
#include "btif/include/btif_sock_sdp.h"
#include "btif/include/btif_sock_thread.h"
#include "btif/include/btif_sock_util.h"
+#include "gd/os/rand.h"
#include "include/hardware/bt_sock.h"
+#include "lpp/lpp_offload_interface.h"
+#include "main/shim/entry.h"
#include "osi/include/allocator.h"
#include "osi/include/compat.h"
#include "osi/include/list.h"
@@ -80,6 +83,7 @@ typedef struct {
int fd;
int app_fd; // Temporary storage for the half of the socketpair that's
// sent back to upper layers.
+ int listen_fd; // listen socket fd from our side
int app_uid; // UID of the app for which this socket was created.
int mtu;
uint8_t* packet;
@@ -92,6 +96,12 @@ typedef struct {
int64_t tx_bytes;
// Cumulative number of bytes received on this socket
int64_t rx_bytes;
+ uint64_t socket_id; // Socket ID in connected state
+ btsock_data_path_t data_path; // socket data path
+ char socket_name[128]; // descriptive socket name
+ uint64_t hub_id; // ID of the hub to which the end point belongs
+ uint64_t endpoint_id; // ID of the hub end point
+ bool is_accepting; // is app accepting on server socket?
} rfc_slot_t;
static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
@@ -106,6 +116,7 @@ static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id);
static uint32_t rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t rfcomm_slot_id);
static bool send_app_scn(rfc_slot_t* rs);
static void handle_discovery_comp(tBTA_JV_STATUS status, int scn, uint32_t id);
+static uint64_t btif_rfc_sock_generate_socket_id();
static bool is_init_done(void) { return pth != -1; }
@@ -227,9 +238,15 @@ static rfc_slot_t* alloc_rfc_slot(const RawAddress* addr, const char* name, cons
slot->fd = fds[0];
slot->app_fd = fds[1];
+ slot->listen_fd = -1;
slot->security = security;
slot->scn = channel;
slot->app_uid = -1;
+ slot->socket_id = 0;
+ slot->data_path = BTSOCK_DATA_PATH_NO_OFFLOAD;
+ slot->hub_id = 0;
+ slot->endpoint_id = 0;
+ slot->is_accepting = false;
slot->is_service_uuid_valid = !uuid.IsEmpty();
slot->service_uuid = uuid;
@@ -270,6 +287,16 @@ static rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs, const RawAddre
accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle);
accept_rs->app_uid = srv_rs->app_uid;
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ accept_rs->socket_id = btif_rfc_sock_generate_socket_id();
+ accept_rs->data_path = srv_rs->data_path;
+ strncpy(accept_rs->socket_name, srv_rs->socket_name, sizeof(accept_rs->socket_name) - 1);
+ accept_rs->socket_name[sizeof(accept_rs->socket_name) - 1] = '\0';
+ accept_rs->hub_id = srv_rs->hub_id;
+ accept_rs->endpoint_id = srv_rs->endpoint_id;
+ accept_rs->listen_fd = srv_rs->fd;
+ }
+
srv_rs->rfc_handle = new_listen_handle;
srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle);
@@ -302,8 +329,32 @@ bt_status_t btsock_rfc_control_req(uint8_t dlci, const RawAddress& bd_addr, uint
return BT_STATUS_SUCCESS;
}
+/// Determine the local MTU for the offloaded RFCOMM connection.
+///
+/// The local MTU is selected as the minimum of:
+/// - The socket hal's offload capabilities (socket_cap.rfcommCapabilities.max_frame_size)
+/// - The application's requested maximum RX packet size (app_max_rx_packet_size)
+///
+/// However, the MTU must be at least the minimum required by the RFCOMM
+/// specification (RFCOMM_MIN_MTU).
+static bool btsock_rfc_get_offload_mtu(int app_max_rx_packet_size, int* rx_mtu) {
+ hal::SocketCapabilities socket_cap =
+ bluetooth::shim::GetLppOffloadManager()->GetSocketCapabilities();
+ if (!socket_cap.rfcomm_capabilities.number_of_supported_sockets) {
+ return false;
+ }
+ // Socket HAL client has already verified that the MTU is in a valid range.
+ int mtu = static_cast<int>(socket_cap.rfcomm_capabilities.max_frame_size);
+ mtu = std::min(mtu, app_max_rx_packet_size);
+ mtu = std::max(mtu, RFCOMM_MIN_MTU);
+ *rx_mtu = mtu;
+ return true;
+}
+
bt_status_t btsock_rfc_listen(const char* service_name, const Uuid* service_uuid, int channel,
- int* sock_fd, int flags, int app_uid) {
+ int* sock_fd, int flags, int app_uid, btsock_data_path_t data_path,
+ const char* socket_name, uint64_t hub_id, uint64_t endpoint_id,
+ int max_rx_packet_size) {
log::assert_that(sock_fd != NULL, "assert failed: sock_fd != NULL");
log::assert_that((service_uuid != NULL) || (channel >= 1 && channel <= MAX_RFC_CHANNEL) ||
((flags & BTSOCK_FLAG_NO_SDP) != 0),
@@ -354,13 +405,33 @@ bt_status_t btsock_rfc_listen(const char* service_name, const Uuid* service_uuid
// close(rs->app_fd);
slot->app_fd = INVALID_FD; // Drop our reference to the fd.
slot->app_uid = app_uid;
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ slot->data_path = data_path;
+ if (socket_name) {
+ strncpy(slot->socket_name, socket_name, sizeof(slot->socket_name) - 1);
+ slot->socket_name[sizeof(slot->socket_name) - 1] = '\0';
+ }
+ slot->hub_id = hub_id;
+ slot->endpoint_id = endpoint_id;
+ if (data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ if (!btsock_rfc_get_offload_mtu(max_rx_packet_size, &slot->mtu)) {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+ }
btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, slot->id);
+ // start monitoring the socketpair to get call back when app is accepting on server socket
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id);
+ }
return BT_STATUS_SUCCESS;
}
bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, const Uuid* service_uuid, int channel,
- int* sock_fd, int flags, int app_uid) {
+ int* sock_fd, int flags, int app_uid, btsock_data_path_t data_path,
+ const char* socket_name, uint64_t hub_id, uint64_t endpoint_id,
+ int max_rx_packet_size) {
log::assert_that(sock_fd != NULL, "assert failed: sock_fd != NULL");
log::assert_that((service_uuid != NULL) || (channel >= 1 && channel <= MAX_RFC_CHANNEL),
"assert failed: (service_uuid != NULL) || (channel >= 1 && channel <= "
@@ -386,8 +457,8 @@ bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, const Uuid* service_uu
}
if (!service_uuid || service_uuid->IsEmpty()) {
- tBTA_JV_STATUS ret =
- BTA_JvRfcommConnect(slot->security, slot->scn, slot->addr, rfcomm_cback, slot->id);
+ tBTA_JV_STATUS ret = BTA_JvRfcommConnect(slot->security, slot->scn, slot->addr, rfcomm_cback,
+ slot->id, RfcommCfgInfo{});
if (ret != tBTA_JV_STATUS::SUCCESS) {
log::error("unable to initiate RFCOMM connection. status:{}, scn:{}, bd_addr:{}",
bta_jv_status_text(ret), slot->scn, slot->addr);
@@ -416,6 +487,20 @@ bt_status_t btsock_rfc_connect(const RawAddress* bd_addr, const Uuid* service_uu
*sock_fd = slot->app_fd; // Transfer ownership of fd to caller.
slot->app_fd = INVALID_FD; // Drop our reference to the fd.
slot->app_uid = app_uid;
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ slot->data_path = data_path;
+ if (socket_name) {
+ strncpy(slot->socket_name, socket_name, sizeof(slot->socket_name) - 1);
+ slot->socket_name[sizeof(slot->socket_name) - 1] = '\0';
+ }
+ slot->hub_id = hub_id;
+ slot->endpoint_id = endpoint_id;
+ if (data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ if (!btsock_rfc_get_offload_mtu(max_rx_packet_size, &slot->mtu)) {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+ }
btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id);
return BT_STATUS_SUCCESS;
@@ -451,8 +536,8 @@ static void cleanup_rfc_slot(rfc_slot_t* slot) {
close(slot->fd);
log::info(
"disconnected from RFCOMM socket connections for device: {}, scn: {}, "
- "app_uid: {}, id: {}",
- slot->addr, slot->scn, slot->app_uid, slot->id);
+ "app_uid: {}, id: {}, socket_id: {}",
+ slot->addr, slot->scn, slot->app_uid, slot->id, slot->socket_id);
btif_sock_connection_logger(
slot->addr, slot->id, BTSOCK_RFCOMM, SOCKET_CONNECTION_STATE_DISCONNECTED,
slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->app_uid, slot->scn,
@@ -460,6 +545,14 @@ static void cleanup_rfc_slot(rfc_slot_t* slot) {
slot->role ? slot->service_name : slot->service_uuid.ToString().c_str());
slot->fd = INVALID_FD;
+
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (slot->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD && !slot->f.server &&
+ slot->socket_id != 0) {
+ bluetooth::shim::GetLppOffloadManager()->SocketClosed(slot->socket_id);
+ slot->socket_id = 0;
+ }
+ }
}
if (slot->app_fd != INVALID_FD) {
@@ -500,7 +593,7 @@ static bool send_app_scn(rfc_slot_t* slot) {
}
static bool send_app_connect_signal(int fd, const RawAddress* addr, int channel, int status,
- int send_fd) {
+ int send_fd, uint64_t socket_id) {
sock_connect_signal_t cs;
cs.size = sizeof(cs);
cs.bd_addr = *addr;
@@ -510,6 +603,7 @@ static bool send_app_connect_signal(int fd, const RawAddress* addr, int channel,
cs.max_tx_packet_size = 0; // not used for RFCOMM
cs.conn_uuid_lsb = 0; // not used for RFCOMM
cs.conn_uuid_msb = 0; // not used for RFCOMM
+ cs.socket_id = socket_id;
if (send_fd == INVALID_FD) {
return sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs);
}
@@ -556,6 +650,52 @@ static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START* p_start, uint32_t id
slot->app_uid, slot->scn, 0, 0, slot->service_name);
}
+static uint32_t on_srv_rfc_connect_offload(tBTA_JV_RFCOMM_SRV_OPEN* p_open, uint32_t id,
+ rfc_slot_t* srv_rs) {
+ rfc_slot_t* accept_rs;
+ accept_rs = create_srv_accept_rfc_slot(srv_rs, &p_open->rem_bda, p_open->handle,
+ p_open->new_listen_handle);
+ if (!accept_rs) {
+ return 0;
+ }
+
+ log::info(
+ "connected to RFCOMM socket connections for device: {}, scn: {}, "
+ "app_uid: {}, id: {}, socket_id: {}",
+ accept_rs->addr, accept_rs->scn, accept_rs->app_uid, id, accept_rs->socket_id);
+ btif_sock_connection_logger(accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM,
+ SOCKET_CONNECTION_STATE_CONNECTED,
+ accept_rs->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+ accept_rs->app_uid, accept_rs->scn, 0, 0, accept_rs->service_name);
+
+ bluetooth::hal::SocketContext socket_context = {
+ .socket_id = accept_rs->socket_id,
+ .name = accept_rs->socket_name,
+ .acl_connection_handle = p_open->acl_handle,
+ .channel_info = bluetooth::hal::RfcommChannelInfo(
+ p_open->local_cid, p_open->remote_cid, p_open->rx_mtu, p_open->tx_mtu,
+ p_open->local_credit, p_open->remote_credit, p_open->dlci, p_open->max_frame_size,
+ p_open->mux_initiator),
+ .endpoint_info.hub_id = accept_rs->hub_id,
+ .endpoint_info.endpoint_id = accept_rs->endpoint_id,
+ };
+ if (!srv_rs->is_accepting) {
+ log::warn("Server socket is not accepting. Disconnect the incoming connection.");
+ cleanup_rfc_slot(accept_rs);
+ } else if (!bluetooth::shim::GetLppOffloadManager()->SocketOpened(socket_context)) {
+ log::warn("RFCOMM socket opened failed. Disconnect the incoming connection.");
+ cleanup_rfc_slot(accept_rs);
+ } else {
+ log::info("RFCOMM socket opened successful. Will send connect signal in async callback.");
+ }
+
+ // Start monitoring the socket.
+ btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id);
+ // start monitoring the socketpair to get call back when app is accepting on server socket
+ btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, srv_rs->id);
+ return srv_rs->id;
+}
+
static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, uint32_t id) {
log::verbose("id:{}", id);
std::unique_lock<std::recursive_mutex> lock(slot_lock);
@@ -566,6 +706,11 @@ static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, uint32_t id)
return 0;
}
+ if (com::android::bluetooth::flags::socket_settings_api() &&
+ srv_rs->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ return on_srv_rfc_connect_offload(p_open, id, srv_rs);
+ }
+
accept_rs = create_srv_accept_rfc_slot(srv_rs, &p_open->rem_bda, p_open->handle,
p_open->new_listen_handle);
if (!accept_rs) {
@@ -574,21 +719,61 @@ static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open, uint32_t id)
log::info(
"connected to RFCOMM socket connections for device: {}, scn: {}, "
- "app_uid: {}, id: {}",
- accept_rs->addr, accept_rs->scn, accept_rs->app_uid, id);
+ "app_uid: {}, id: {}, socket_id: {}",
+ accept_rs->addr, accept_rs->scn, accept_rs->app_uid, id, accept_rs->socket_id);
btif_sock_connection_logger(accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM,
- SOCKET_CONNECTION_STATE_DISCONNECTED,
+ SOCKET_CONNECTION_STATE_CONNECTED,
accept_rs->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
accept_rs->app_uid, accept_rs->scn, 0, 0, accept_rs->service_name);
// Start monitoring the socket.
btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id);
btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id);
- send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd);
+ send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd,
+ accept_rs->socket_id);
accept_rs->app_fd = INVALID_FD; // Ownership of the application fd has been transferred.
+ // start monitoring the socketpair to get call back when app is accepting on server socket
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, srv_rs->id);
+ }
return srv_rs->id;
}
+static void on_cli_rfc_connect_offload(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id, rfc_slot_t* slot) {
+ slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
+ slot->addr = p_open->rem_bda;
+ slot->socket_id = btif_rfc_sock_generate_socket_id();
+
+ log::info(
+ "connected to RFCOMM socket connections for device: {}, scn: {}, "
+ "app_uid: {}, id: {}, socket_id: {}",
+ slot->addr, slot->scn, slot->app_uid, id, slot->socket_id);
+ btif_sock_connection_logger(
+ slot->addr, slot->id, BTSOCK_RFCOMM, SOCKET_CONNECTION_STATE_CONNECTED,
+ slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->app_uid, slot->scn, 0,
+ 0, slot->service_uuid.ToString().c_str());
+
+ bluetooth::hal::SocketContext socket_context = {
+ .socket_id = slot->socket_id,
+ .name = slot->socket_name,
+ .acl_connection_handle = p_open->acl_handle,
+ .channel_info = bluetooth::hal::RfcommChannelInfo(
+ p_open->local_cid, p_open->remote_cid, p_open->rx_mtu, p_open->tx_mtu,
+ p_open->local_credit, p_open->remote_credit, p_open->dlci, p_open->max_frame_size,
+ p_open->mux_initiator),
+ .endpoint_info.hub_id = slot->hub_id,
+ .endpoint_info.endpoint_id = slot->endpoint_id,
+ };
+ if (!bluetooth::shim::GetLppOffloadManager()->SocketOpened(socket_context)) {
+ log::warn("RFCOMM socket opened failed. Disconnect the incoming connection.");
+ cleanup_rfc_slot(slot);
+ } else {
+ log::info(
+ "RFCOMM socket opened successful. Will send connect signal in "
+ "on_btsocket_rfc_opened_complete() asynchronously.");
+ }
+}
+
static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) {
log::verbose("id:{}", id);
std::unique_lock<std::recursive_mutex> lock(slot_lock);
@@ -605,25 +790,102 @@ static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) {
return;
}
+ if (com::android::bluetooth::flags::socket_settings_api() &&
+ slot->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ on_cli_rfc_connect_offload(p_open, id, slot);
+ return;
+ }
+
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
slot->addr = p_open->rem_bda;
+ slot->socket_id = btif_rfc_sock_generate_socket_id();
log::info(
"connected to RFCOMM socket connections for device: {}, scn: {}, "
- "app_uid: {}, id: {}",
- slot->addr, slot->scn, slot->app_uid, id);
+ "app_uid: {}, id: {}, socket_id: {}",
+ slot->addr, slot->scn, slot->app_uid, id, slot->socket_id);
btif_sock_connection_logger(
slot->addr, slot->id, BTSOCK_RFCOMM, SOCKET_CONNECTION_STATE_CONNECTED,
slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->app_uid, slot->scn, 0,
0, slot->service_uuid.ToString().c_str());
- if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1)) {
+ if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1, slot->socket_id)) {
slot->f.connected = true;
} else {
log::error("unable to send connect completion signal to caller.");
}
}
+/* only call with slot_lock taken */
+static rfc_slot_t* find_rfc_slot_by_socket_id(uint64_t socket_id) {
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) {
+ if (rfc_slots[i].socket_id == socket_id) {
+ return &rfc_slots[i];
+ }
+ }
+
+ return nullptr;
+}
+
+bool btsock_rfc_in_use(uint64_t socket_id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ return find_rfc_slot_by_socket_id(socket_id) != nullptr;
+}
+
+void on_btsocket_rfc_opened_complete(uint64_t socket_id, bool success) {
+ rfc_slot_t* slot;
+
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ slot = find_rfc_slot_by_socket_id(socket_id);
+ if (!slot) {
+ log::error("Unable to find rfcomm socket with socket_id: {}", socket_id);
+ return;
+ }
+ if (!success) {
+ log::error("RFCOMM opened complete failed with socket_id: {}", socket_id);
+ cleanup_rfc_slot(slot);
+ return;
+ }
+ // If the socket was accepted from listen socket, use listen_fd.
+ if (slot->listen_fd != -1) {
+ send_app_connect_signal(slot->listen_fd, &slot->addr, slot->scn, 0, slot->app_fd,
+ slot->socket_id);
+ // The fd is closed after sent to app in send_app_connect_signal()
+ slot->app_fd = -1;
+ } else {
+ if (!send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1, slot->socket_id)) {
+ log::error("Unable to connect rfcomm socket to application socket_id: {}", slot->id);
+ return;
+ }
+
+ log::info("Connected rfcomm socket socket_id: {}", slot->id);
+ slot->f.connected = true;
+ }
+}
+
+void on_btsocket_rfc_close(uint64_t socket_id) {
+ rfc_slot_t* slot;
+
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ slot = find_rfc_slot_by_socket_id(socket_id);
+ if (!slot) {
+ log::error("Unable to find rfcomm socket with socket_id: {}", socket_id);
+ return;
+ }
+ log::info("RFCOMM close request for socket_id: {}", socket_id);
+ cleanup_rfc_slot(slot);
+}
+
+// TODO(b/380189525): Replace the randomized socket ID with static counter when we don't have
+// security concerns about using static counter.
+static uint64_t btif_rfc_sock_generate_socket_id() {
+ uint64_t socket_id;
+ do {
+ socket_id = bluetooth::os::GenerateRandomUint64();
+ } while (!socket_id);
+ return socket_id;
+}
+
static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE* /* p_close */, uint32_t id) {
log::verbose("id:{}", id);
std::unique_lock<std::recursive_mutex> lock(slot_lock);
@@ -768,8 +1030,21 @@ static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) {
log::debug(
"Since UUID is not valid; not setting SDP-record and just starting "
"the RFCOMM server");
+ // Setup optional configurations
+ RfcommCfgInfo cfg = {};
+ // For hardware offload data path, host stack sets the initial credits to 0. The offload
+ // stack should send initial credits to peer device through RFCOMM signaling command when
+ // the data path is switched successfully.
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (rs->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ cfg.init_credit_present = true;
+ cfg.init_credit = 0;
+ cfg.rx_mtu_present = rs->mtu > 0;
+ cfg.rx_mtu = rs->mtu;
+ }
+ }
// now start the rfcomm server after sdp & channel # assigned
- BTA_JvRfcommStartServer(rs->security, rs->scn, MAX_RFC_SESSION, rfcomm_cback, rs->id);
+ BTA_JvRfcommStartServer(rs->security, rs->scn, MAX_RFC_SESSION, rfcomm_cback, rs->id, cfg);
}
break;
}
@@ -795,8 +1070,22 @@ static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) {
break;
}
+ // Setup optional configurations
+ RfcommCfgInfo cfg = {};
+ // For hardware offload data path, host stack sets the initial credits to 0. The offload
+ // stack should send initial credits to peer device through RFCOMM signaling command when
+ // the data path is switched successfully.
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (slot->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ cfg.init_credit_present = true;
+ cfg.init_credit = 0;
+ cfg.rx_mtu_present = slot->mtu > 0;
+ cfg.rx_mtu = slot->mtu;
+ }
+ }
// Start the rfcomm server after sdp & channel # assigned.
- BTA_JvRfcommStartServer(slot->security, slot->scn, MAX_RFC_SESSION, rfcomm_cback, slot->id);
+ BTA_JvRfcommStartServer(slot->security, slot->scn, MAX_RFC_SESSION, rfcomm_cback, slot->id,
+ cfg);
break;
}
@@ -840,7 +1129,21 @@ static void handle_discovery_comp(tBTA_JV_STATUS status, int scn, uint32_t id) {
return;
}
- if (BTA_JvRfcommConnect(slot->security, scn, slot->addr, rfcomm_cback, slot->id) !=
+ // Setup optional configurations
+ RfcommCfgInfo cfg = {};
+ // For hardware offload data path, host stack sets the initial credits to 0. The offload
+ // stack should send initial credits to peer device through RFCOMM signaling command when
+ // the data path is switched successfully.
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ if (slot->data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) {
+ cfg.init_credit_present = true;
+ cfg.init_credit = 0;
+ cfg.rx_mtu_present = slot->mtu > 0;
+ cfg.rx_mtu = slot->mtu;
+ }
+ }
+
+ if (BTA_JvRfcommConnect(slot->security, scn, slot->addr, rfcomm_cback, slot->id, cfg) !=
tBTA_JV_STATUS::SUCCESS) {
log::warn(
"BTA_JvRfcommConnect() returned BTA_JV_FAILURE for RFCOMM slot with "
@@ -926,7 +1229,94 @@ static bool flush_incoming_que_on_wr_signal(rfc_slot_t* slot) {
return true;
}
-void btsock_rfc_signaled(int /* fd */, int flags, uint32_t id) {
+static bool btsock_rfc_read_signaled_on_connected_socket(int /* fd */, int flags, uint32_t /* id */,
+ rfc_slot_t* slot) {
+ if (!slot->f.connected) {
+ log::error("socket signaled for read while disconnected, slot: {}, channel: {}", slot->id,
+ slot->scn);
+ return false;
+ }
+ // Make sure there's data pending in case the peer closed the socket.
+ int size = 0;
+ if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl(slot->fd, FIONREAD, &size) == 0 && size)) {
+ BTA_JvRfcommWrite(slot->rfc_handle, slot->id);
+ }
+ return true;
+}
+
+static bool btsock_rfc_read_signaled_on_listen_socket(int fd, int /* flags */, uint32_t /* id */,
+ rfc_slot_t* slot) {
+ int size = 0;
+ bool ioctl_success = ioctl(slot->fd, FIONREAD, &size) == 0;
+ if (ioctl_success && size) {
+ sock_accept_signal_t accept_signal = {};
+ ssize_t count;
+ OSI_NO_INTR(count = recv(fd, reinterpret_cast<uint8_t*>(&accept_signal), sizeof(accept_signal),
+ MSG_NOSIGNAL | MSG_DONTWAIT | MSG_TRUNC));
+ if (count != sizeof(accept_signal) || count != accept_signal.size) {
+ log::error("Unexpected count: {}, sizeof(accept_signal): {}, accept_signal.size: {}", count,
+ sizeof(accept_signal), accept_signal.size);
+ return false;
+ }
+ slot->is_accepting = accept_signal.is_accepting;
+ log::info("Server socket: {}, is_accepting: {}", slot->id, slot->is_accepting);
+ }
+ return true;
+}
+
+static void btsock_rfc_signaled_flagged(int fd, int flags, uint32_t id) {
+ bool need_close = false;
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) {
+ log::warn("RFCOMM slot with id {} not found.", id);
+ return;
+ }
+
+ // Data available from app, tell stack we have outgoing data.
+ if (flags & SOCK_THREAD_FD_RD) {
+ if (!slot->f.server) {
+ // app sending data on connection socket
+ if (!btsock_rfc_read_signaled_on_connected_socket(fd, flags, id, slot)) {
+ need_close = true;
+ }
+ } else {
+ // app sending signal on listen socket
+ if (!btsock_rfc_read_signaled_on_listen_socket(fd, flags, id, slot)) {
+ need_close = true;
+ }
+ }
+ }
+
+ if (flags & SOCK_THREAD_FD_WR) {
+ // App is ready to receive more data, tell stack to enable data flow.
+ if (!slot->f.connected || !flush_incoming_que_on_wr_signal(slot)) {
+ log::error(
+ "socket signaled for write while disconnected (or write failure), "
+ "slot: {}, channel: {}",
+ slot->id, slot->scn);
+ need_close = true;
+ }
+ }
+
+ if (need_close || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+ // Clean up if there's no data pending.
+ int size = 0;
+ if (need_close || ioctl(slot->fd, FIONREAD, &size) != 0 || !size) {
+ if (com::android::bluetooth::flags::rfcomm_cancel_ongoing_sdp_on_close() &&
+ slot->f.doing_sdp_request) {
+ BTA_JvCancelDiscovery(slot->id);
+ }
+ cleanup_rfc_slot(slot);
+ }
+ }
+}
+
+void btsock_rfc_signaled(int fd, int flags, uint32_t id) {
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ btsock_rfc_signaled_flagged(fd, flags, id);
+ return;
+ }
bool need_close = false;
std::unique_lock<std::recursive_mutex> lock(slot_lock);
rfc_slot_t* slot = find_rfc_slot_by_id(id);
diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc
index 9300c23334..e51756483c 100644
--- a/system/btif/src/btif_storage.cc
+++ b/system/btif/src/btif_storage.cc
@@ -452,7 +452,6 @@ static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t* p_bonded_
memset(p_bonded_devices, 0, sizeof(btif_bonded_devices_t));
bool bt_linkkey_file_found = false;
- int device_type;
for (const auto& bd_addr : btif_config_get_paired_devices()) {
auto name = bd_addr.ToString();
@@ -473,6 +472,7 @@ static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t* p_bonded_
btif_config_get_int(name, BTIF_STORAGE_KEY_PIN_LENGTH, &pin_length);
BTA_DmAddDevice(bd_addr, dev_class, link_key, (uint8_t)linkkey_type, pin_length);
+ int device_type = BT_DEVICE_TYPE_UNKNOWN;
if (btif_config_get_int(name, BTIF_STORAGE_KEY_DEV_TYPE, &device_type) &&
(device_type == BT_DEVICE_TYPE_DUMO)) {
btif_gatts_add_bonded_dev_from_nv(bd_addr);
@@ -1190,7 +1190,7 @@ bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, Octet16* key_value)
bt_status_t btif_in_fetch_bonded_ble_device(const std::string& remote_bd_addr, int add,
btif_bonded_devices_t* p_bonded_devices) {
- int device_type;
+ int device_type = BT_DEVICE_TYPE_UNKNOWN;
tBLE_ADDR_TYPE addr_type;
bool device_added = false;
bool key_found = false;
@@ -1272,7 +1272,7 @@ bool btif_has_ble_keys(const std::string& bdstr) {
******************************************************************************/
bt_status_t btif_storage_get_remote_addr_type(const RawAddress* remote_bd_addr,
tBLE_ADDR_TYPE* addr_type) {
- int val;
+ int val = BLE_ADDR_ANONYMOUS;
bool ret = btif_config_get_int(remote_bd_addr->ToString(), BTIF_STORAGE_KEY_ADDR_TYPE, &val);
*addr_type = static_cast<tBLE_ADDR_TYPE>(val);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
@@ -1443,7 +1443,7 @@ void btif_debug_linkkey_type_dump(int fd) {
for (const auto& bd_addr : btif_config_get_paired_devices()) {
auto bdstr = bd_addr.ToString();
int linkkey_type;
- dprintf(fd, " %s\n", ADDRESS_TO_LOGGABLE_CSTR(bd_addr));
+ dprintf(fd, " %s\n", bd_addr.ToRedactedStringForLogging().c_str());
dprintf(fd, " BR: ");
if (btif_config_get_int(bdstr, BTIF_STORAGE_KEY_LINK_KEY_TYPE, &linkkey_type)) {
diff --git a/system/btif/src/stack_manager.cc b/system/btif/src/stack_manager.cc
index ace7f8e7e2..288cbfcdf3 100644
--- a/system/btif/src/stack_manager.cc
+++ b/system/btif/src/stack_manager.cc
@@ -330,10 +330,10 @@ static void event_start_up_stack(bluetooth::core::CoreInterface* interface,
if (!com::android::bluetooth::flags::scan_manager_refactor()) {
info("Starting rust module");
module_start_up(get_local_module(RUST_MODULE));
- }
- if (com::android::bluetooth::flags::channel_sounding_in_stack()) {
- bluetooth::ras::GetRasServer()->Initialize();
- bluetooth::ras::GetRasClient()->Initialize();
+ if (com::android::bluetooth::flags::channel_sounding_in_stack()) {
+ bluetooth::ras::GetRasServer()->Initialize();
+ bluetooth::ras::GetRasClient()->Initialize();
+ }
}
stack_is_running = true;
@@ -395,6 +395,11 @@ static void event_shut_down_stack(ProfileStopCallback stopProfiles) {
static void event_start_up_rust_module(std::promise<void> promise) {
info("is bringing up the Rust module");
module_start_up(get_local_module(RUST_MODULE));
+ if (com::android::bluetooth::flags::channel_sounding_in_stack()) {
+ // GATT server requires the rust module to be running
+ bluetooth::ras::GetRasServer()->Initialize();
+ bluetooth::ras::GetRasClient()->Initialize();
+ }
promise.set_value();
info("finished");
}
diff --git a/system/btif/test/btif_core_test.cc b/system/btif/test/btif_core_test.cc
index 8d78ce68cf..66881a92d8 100644
--- a/system/btif/test/btif_core_test.cc
+++ b/system/btif/test/btif_core_test.cc
@@ -1022,9 +1022,14 @@ TEST_F(BtifCoreSocketTest, CreateRfcommServerSocket) {
static constexpr int kAppUid = 3;
const Uuid server_uuid = Uuid::From16Bit(UUID_SERVCLASS_SERIAL_PORT);
int socket_number = 0;
+ btsock_data_path_t data_path = BTSOCK_DATA_PATH_NO_OFFLOAD;
+ uint64_t hub_id = 0;
+ uint64_t endpoint_id = 0;
+ int max_rx_packet_size = 0;
ASSERT_EQ(BT_STATUS_SUCCESS,
- btif_sock_get_interface()->listen(BTSOCK_RFCOMM, "TestService", &server_uuid,
- kChannelOne, &socket_number, kFlags, kAppUid));
+ btif_sock_get_interface()->listen(
+ BTSOCK_RFCOMM, "TestService", &server_uuid, kChannelOne, &socket_number, kFlags,
+ kAppUid, data_path, "TestSocket", hub_id, endpoint_id, max_rx_packet_size));
}
TEST_F(BtifCoreSocketTest, CreateTwoRfcommServerSockets) {
@@ -1033,9 +1038,14 @@ TEST_F(BtifCoreSocketTest, CreateTwoRfcommServerSockets) {
static constexpr int kAppUid = 3;
const Uuid server_uuid = Uuid::From16Bit(UUID_SERVCLASS_SERIAL_PORT);
int socket_number = 0;
+ btsock_data_path_t data_path = BTSOCK_DATA_PATH_NO_OFFLOAD;
+ uint64_t hub_id = 0;
+ uint64_t endpoint_id = 0;
+ int max_rx_packet_size = 0;
ASSERT_EQ(BT_STATUS_SUCCESS,
- btif_sock_get_interface()->listen(BTSOCK_RFCOMM, "TestService", &server_uuid,
- kChannelOne, &socket_number, kFlags, kAppUid));
+ btif_sock_get_interface()->listen(
+ BTSOCK_RFCOMM, "TestService", &server_uuid, kChannelOne, &socket_number, kFlags,
+ kAppUid, data_path, "TestSocket", hub_id, endpoint_id, max_rx_packet_size));
static constexpr int kChannelTwo = 2;
static constexpr int kFlagsTwo = 4;
static constexpr int kAppUidTwo = 6;
@@ -1043,7 +1053,8 @@ TEST_F(BtifCoreSocketTest, CreateTwoRfcommServerSockets) {
int socket_number_two = 1;
ASSERT_EQ(BT_STATUS_SUCCESS, btif_sock_get_interface()->listen(
BTSOCK_RFCOMM, "ServiceTwo", &server_uuid_two, kChannelTwo,
- &socket_number_two, kFlagsTwo, kAppUidTwo));
+ &socket_number_two, kFlagsTwo, kAppUidTwo, data_path,
+ "TestSocket", hub_id, endpoint_id, max_rx_packet_size));
}
TEST_F(BtifCoreSocketTest, CreateManyRfcommServerSockets) {
@@ -1059,9 +1070,14 @@ TEST_F(BtifCoreSocketTest, CreateManyRfcommServerSockets) {
server_uuid_str[1] = (i / 100) % 10 + '0';
server_uuid_str[0] = (i / 1000) % 10 + '0';
Uuid server_uuid = Uuid::FromString(server_uuid_str);
+ btsock_data_path_t data_path = BTSOCK_DATA_PATH_NO_OFFLOAD;
+ uint64_t hub_id = 0;
+ uint64_t endpoint_id = 0;
+ int max_rx_packet_size = 0;
ASSERT_EQ(BT_STATUS_SUCCESS,
- btif_sock_get_interface()->listen(BTSOCK_RFCOMM, "TestService", &server_uuid, channel,
- &socket_number, flags, app_uuid));
+ btif_sock_get_interface()->listen(
+ BTSOCK_RFCOMM, "TestService", &server_uuid, channel, &socket_number, flags,
+ app_uuid, data_path, "TestSocket", hub_id, endpoint_id, max_rx_packet_size));
ASSERT_EQ(0, close(socket_number));
}
}
diff --git a/system/common/Android.bp b/system/common/Android.bp
index 4bc0bebf2d..f3f2a619ca 100644
--- a/system/common/Android.bp
+++ b/system/common/Android.bp
@@ -20,6 +20,7 @@ cc_library_static {
],
srcs: [
"address_obfuscator.cc",
+ "le_conn_params.cc",
"message_loop_thread.cc",
"metric_id_allocator.cc",
"os_utils.cc",
diff --git a/system/common/BUILD.gn b/system/common/BUILD.gn
index 8352d2bcc4..a1884973dd 100644
--- a/system/common/BUILD.gn
+++ b/system/common/BUILD.gn
@@ -17,6 +17,7 @@
static_library("common") {
sources = [
"address_obfuscator.cc",
+ "le_conn_params.cc",
"message_loop_thread.cc",
"metric_id_allocator.cc",
"metrics_linux.cc",
diff --git a/system/common/le_conn_params.cc b/system/common/le_conn_params.cc
new file mode 100644
index 0000000000..0cfc3675a0
--- /dev/null
+++ b/system/common/le_conn_params.cc
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "le_conn_params"
+
+#include "common/le_conn_params.h"
+
+#include <bluetooth/log.h>
+
+#include <cstdint>
+
+#include "os/system_properties.h"
+#include "stack/include/btm_ble_api_types.h"
+
+using namespace bluetooth;
+
+const std::string LeConnectionParameters::kPropertyAggressiveConnThreshold =
+ "bluetooth.core.le.aggressive_connection_threshold";
+const std::string LeConnectionParameters::kPropertyMinConnIntervalAggressive =
+ "bluetooth.core.le.min_connection_interval_aggressive";
+const std::string LeConnectionParameters::kPropertyMaxConnIntervalAggressive =
+ "bluetooth.core.le.max_connection_interval_aggressive";
+const std::string LeConnectionParameters::kPropertyMinConnIntervalRelaxed =
+ "bluetooth.core.le.min_connection_interval_relaxed";
+const std::string LeConnectionParameters::kPropertyMaxConnIntervalRelaxed =
+ "bluetooth.core.le.max_connection_interval_relaxed";
+
+bool LeConnectionParameters::initialized = false;
+uint32_t LeConnectionParameters::aggressive_conn_threshold = kAggressiveConnThreshold;
+uint32_t LeConnectionParameters::min_conn_interval_aggressive = kMinConnIntervalAggressive;
+uint32_t LeConnectionParameters::max_conn_interval_aggressive = kMaxConnIntervalAggressive;
+uint32_t LeConnectionParameters::min_conn_interval_relaxed = kMinConnIntervalRelaxed;
+uint32_t LeConnectionParameters::max_conn_interval_relaxed = kMaxConnIntervalRelaxed;
+
+void LeConnectionParameters::InitConnParamsWithSystemProperties() {
+ aggressive_conn_threshold =
+ os::GetSystemPropertyUint32(kPropertyAggressiveConnThreshold, kAggressiveConnThreshold);
+ min_conn_interval_aggressive = os::GetSystemPropertyUint32(kPropertyMinConnIntervalAggressive,
+ kMinConnIntervalAggressive);
+ max_conn_interval_aggressive = os::GetSystemPropertyUint32(kPropertyMaxConnIntervalAggressive,
+ kMaxConnIntervalAggressive);
+ min_conn_interval_relaxed =
+ os::GetSystemPropertyUint32(kPropertyMinConnIntervalRelaxed, kMinConnIntervalRelaxed);
+ max_conn_interval_relaxed =
+ os::GetSystemPropertyUint32(kPropertyMaxConnIntervalRelaxed, kMaxConnIntervalRelaxed);
+
+ log::debug("Before checking validity: threshold={}, aggressive={}/{}, relaxed={}/{}",
+ aggressive_conn_threshold, min_conn_interval_aggressive, max_conn_interval_aggressive,
+ min_conn_interval_relaxed, max_conn_interval_relaxed);
+
+ // Check validity of each values
+ if (aggressive_conn_threshold < 0) {
+ log::warn("Invalid aggressive connection threshold. Using default value.",
+ aggressive_conn_threshold);
+ aggressive_conn_threshold = kAggressiveConnThreshold;
+ }
+
+ if (min_conn_interval_aggressive < BTM_BLE_CONN_INT_MIN ||
+ min_conn_interval_aggressive > BTM_BLE_CONN_INT_MAX ||
+ max_conn_interval_aggressive < BTM_BLE_CONN_INT_MIN ||
+ max_conn_interval_aggressive > BTM_BLE_CONN_INT_MAX ||
+ max_conn_interval_aggressive < min_conn_interval_aggressive) {
+ log::warn("Invalid aggressive connection intervals. Using default values.");
+ min_conn_interval_aggressive = kMinConnIntervalAggressive;
+ max_conn_interval_aggressive = kMaxConnIntervalAggressive;
+ }
+
+ if (min_conn_interval_relaxed < BTM_BLE_CONN_INT_MIN ||
+ min_conn_interval_relaxed > BTM_BLE_CONN_INT_MAX ||
+ max_conn_interval_relaxed < BTM_BLE_CONN_INT_MIN ||
+ max_conn_interval_relaxed > BTM_BLE_CONN_INT_MAX ||
+ max_conn_interval_relaxed < min_conn_interval_relaxed) {
+ log::warn("Invalid relaxed connection intervals. Using default values.");
+ min_conn_interval_relaxed = kMinConnIntervalRelaxed;
+ max_conn_interval_relaxed = kMaxConnIntervalRelaxed;
+ }
+
+ if ((min_conn_interval_aggressive > min_conn_interval_relaxed) &&
+ (max_conn_interval_aggressive > max_conn_interval_relaxed)) {
+ log::warn(
+ "Relaxed connection intervals are more aggressive than aggressive ones."
+ " Setting all intervals to default values.");
+ min_conn_interval_aggressive = kMinConnIntervalAggressive;
+ max_conn_interval_aggressive = kMaxConnIntervalAggressive;
+ min_conn_interval_relaxed = kMinConnIntervalRelaxed;
+ max_conn_interval_relaxed = kMaxConnIntervalRelaxed;
+ }
+
+ log::debug("After checking validity: threshold={}, aggressive={}/{}, relaxed={}/{}",
+ aggressive_conn_threshold, min_conn_interval_aggressive, max_conn_interval_aggressive,
+ min_conn_interval_relaxed, max_conn_interval_relaxed);
+
+ initialized = true;
+}
+
+uint32_t LeConnectionParameters::GetAggressiveConnThreshold() {
+ if (!initialized) {
+ InitConnParamsWithSystemProperties();
+ }
+ return aggressive_conn_threshold;
+}
+
+uint32_t LeConnectionParameters::GetMinConnIntervalAggressive() {
+ if (!initialized) {
+ InitConnParamsWithSystemProperties();
+ }
+ return min_conn_interval_aggressive;
+}
+
+uint32_t LeConnectionParameters::GetMaxConnIntervalAggressive() {
+ if (!initialized) {
+ InitConnParamsWithSystemProperties();
+ }
+ return max_conn_interval_aggressive;
+}
+
+uint32_t LeConnectionParameters::GetMinConnIntervalRelaxed() {
+ if (!initialized) {
+ InitConnParamsWithSystemProperties();
+ }
+ return min_conn_interval_relaxed;
+}
+
+uint32_t LeConnectionParameters::GetMaxConnIntervalRelaxed() {
+ if (!initialized) {
+ InitConnParamsWithSystemProperties();
+ }
+ return max_conn_interval_relaxed;
+}
diff --git a/system/common/le_conn_params.h b/system/common/le_conn_params.h
new file mode 100644
index 0000000000..2365742ac2
--- /dev/null
+++ b/system/common/le_conn_params.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bluetooth/log.h>
+
+#include <cstdint>
+
+class LeConnectionParameters {
+public:
+ static constexpr uint16_t kAggressiveConnThreshold = 2;
+ static constexpr uint16_t kMinConnIntervalAggressive = 0x0008; // 8, *1.25 becomes 10ms
+ static constexpr uint16_t kMaxConnIntervalAggressive = 0x0010; // 16, *1.25 becomes 20ms
+ static constexpr uint16_t kMinConnIntervalRelaxed = 0x0018; // 24, *1.25 becomes 30ms
+ static constexpr uint16_t kMaxConnIntervalRelaxed = 0x0028; // 40, *1.25 becomes 50ms
+
+ static const std::string kPropertyAggressiveConnThreshold;
+ static const std::string kPropertyMinConnIntervalAggressive;
+ static const std::string kPropertyMaxConnIntervalAggressive;
+ static const std::string kPropertyMinConnIntervalRelaxed;
+ static const std::string kPropertyMaxConnIntervalRelaxed;
+
+ static void InitConnParamsWithSystemProperties();
+ static uint32_t GetAggressiveConnThreshold();
+ static uint32_t GetMinConnIntervalAggressive();
+ static uint32_t GetMaxConnIntervalAggressive();
+ static uint32_t GetMinConnIntervalRelaxed();
+ static uint32_t GetMaxConnIntervalRelaxed();
+
+private:
+ static bool initialized;
+ static uint32_t aggressive_conn_threshold;
+ static uint32_t min_conn_interval_aggressive;
+ static uint32_t max_conn_interval_aggressive;
+ static uint32_t min_conn_interval_relaxed;
+ static uint32_t max_conn_interval_relaxed;
+};
diff --git a/system/common/message_loop_thread.cc b/system/common/message_loop_thread.cc
index 3cf5f1af38..1de1ff036e 100644
--- a/system/common/message_loop_thread.cc
+++ b/system/common/message_loop_thread.cc
@@ -18,7 +18,6 @@
#include <base/functional/callback.h>
#include <base/location.h>
-#include <base/strings/stringprintf.h>
#include <base/time/time.h>
#include <bluetooth/log.h>
#include <sys/syscall.h>
@@ -130,7 +129,7 @@ std::string MessageLoopThread::GetName() const { return thread_name_; }
std::string MessageLoopThread::ToString() const {
std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
- return base::StringPrintf("%s(%d)", thread_name_.c_str(), thread_id_);
+ return std::format("{}({})", thread_name_, thread_id_);
}
bool MessageLoopThread::IsRunning() const {
diff --git a/system/device/Android.bp b/system/device/Android.bp
index 5411561278..eb71e3f414 100644
--- a/system/device/Android.bp
+++ b/system/device/Android.bp
@@ -29,9 +29,6 @@ cc_library_static {
apex_available: [
"com.android.btservices",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
min_sdk_version: "Tiramisu",
header_libs: ["libbluetooth_headers"],
static_libs: [
diff --git a/system/device/fuzzer/Android.bp b/system/device/fuzzer/Android.bp
index d1b7357de9..c7a6917898 100644
--- a/system/device/fuzzer/Android.bp
+++ b/system/device/fuzzer/Android.bp
@@ -40,9 +40,6 @@ cc_fuzz {
"liblog",
"server_configurable_flags",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
static_libs: [
"bluetooth_flags_c_lib",
"libbluetooth-types",
diff --git a/system/gd/Android.bp b/system/gd/Android.bp
index 9ac1e58995..aae5f1deb2 100644
--- a/system/gd/Android.bp
+++ b/system/gd/Android.bp
@@ -87,6 +87,7 @@ cc_defaults {
srcs: [
":BluetoothHalSources_hci_host",
":BluetoothHalSources_ranging_host",
+ ":BluetoothHalSources_socket_host",
":BluetoothOsSources_host",
":BluetoothSyspropsSources",
],
@@ -95,6 +96,7 @@ cc_defaults {
srcs: [
":BluetoothHalSources_hci_android_hidl",
":BluetoothHalSources_ranging_android",
+ ":BluetoothHalSources_socket_android",
":BluetoothOsSources_android",
],
shared_libs: [
@@ -117,27 +119,22 @@ cc_defaults {
whole_static_libs: [
"android.hardware.bluetooth-V1-ndk",
"android.hardware.bluetooth.ranging-V2-ndk",
+ "android.hardware.bluetooth.socket-V1-ndk",
+ "android.hardware.contexthub-V4-ndk",
],
},
},
srcs: [
":BluetoothCommonSources",
- ":BluetoothDumpsysSources",
":BluetoothHalSources",
":BluetoothHciSources",
+ ":BluetoothLppOffloadSources",
":BluetoothMetricsSources",
":BluetoothNeighborSources",
":BluetoothOsSources",
":BluetoothPacketSources",
- ":BluetoothShimSources",
":BluetoothStorageSources",
"module.cc",
- "module_dumper.cc",
- "stack_manager.cc",
- ],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
],
shared_libs: [
"libcrypto",
@@ -156,7 +153,6 @@ cc_defaults {
static_libs: [
"libaconfig_storage_read_api_cc",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-protos",
"libbluetooth-types",
"libbluetooth_crypto_toolbox",
@@ -238,98 +234,6 @@ cc_library_static {
],
}
-cc_binary {
- name: "bluetooth_stack_with_facade",
- defaults: [
- "gd_defaults",
- ],
- cflags: [
- // The generated gRPC code triggers these warnings.
- "-Wno-missing-prototypes",
- ],
- include_dirs: [
- "packages/modules/Bluetooth/system",
- "packages/modules/Bluetooth/system/include",
- ],
- host_supported: true,
- srcs: [
- ":BluetoothFacade_hci_hal",
- ":BluetoothFacade_hci_layer",
- ":BluetoothFacade_neighbor",
- ":TestMockMainShimStack",
- "facade/facade_main.cc",
- "facade/grpc_root_server.cc",
- "facade/read_only_property_server.cc",
- "grpc/grpc_module.cc",
- ],
- generated_headers: [
- "BlueberryFacadeGeneratedStub_h",
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
- generated_sources: [
- "BlueberryFacadeGeneratedStub_cc",
- ],
- static_libs: [
- "bluetooth_flags_c_lib",
- "breakpad_client",
- "libPlatformProperties",
- "libbluetooth-dumpsys",
- "libbluetooth-protos",
- "libbluetooth-types",
- "libbluetooth_crypto_toolbox",
- "libbluetooth_gd",
- "libbluetooth_hci_pdl",
- "libbluetooth_l2cap_pdl",
- "libbluetooth_log",
- "libbluetooth_ras_pdl",
- "libbluetooth_smp_pdl",
- "libbt-common",
- "libchrome",
- "libcom.android.sysprop.bluetooth.wrapped",
- "libflatbuffers-cpp",
- "libosi",
- ],
- shared_libs: [
- "libaconfig_storage_read_api_cc",
- "libbase",
- "libcrypto",
- "libgrpc++",
- "libgrpc_wrap",
- "liblog",
- "libprotobuf-cpp-full",
- "libunwindstack",
- "server_configurable_flags",
- ],
- target: {
- android: {
- shared_libs: [
- "android.hardware.bluetooth@1.0",
- "android.hardware.bluetooth@1.1",
- "libbinder_ndk",
- "libcutils",
- "libhidlbase",
- "libstatssocket",
- "libutils",
- ],
- static_libs: [
- "android.system.suspend-V1-ndk",
- "android.system.suspend.control-V1-ndk",
- "libstatslog_bt",
- ],
- },
- host: {
- required: [
- "root-canal",
- ],
- },
- },
- sanitize: {
- address: true,
- cfi: true,
- },
-}
-
cc_test {
name: "bluetooth_test_with_timerfd",
test_suites: ["general-tests"],
@@ -363,6 +267,7 @@ cc_test {
"libchrome",
"libgmock",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
shared_libs: [
"libbase",
@@ -430,14 +335,9 @@ cc_test {
":BluetoothOsTestSources",
":BluetoothPacketTestSources",
":BluetoothStorageUnitTestSources",
+ ":TestCommonMockFunctions",
+ ":TestMockStackMetrics",
"module_unittest.cc",
- "stack_manager_unittest.cc",
- ],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- "BluetoothGeneratedDumpsysInternalTestData_h",
- "BluetoothGeneratedDumpsysTestData_h",
],
static_libs: [
"bluetooth_flags_c_lib_for_test",
@@ -541,9 +441,6 @@ cc_defaults {
"libosi",
],
host_supported: true,
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
shared_libs: [
"libPlatformProperties",
"libaconfig_storage_read_api_cc",
@@ -600,8 +497,16 @@ cc_fuzz {
name: "bluetooth_gd_acl_manager_fuzz_test",
defaults: ["gd_fuzz_defaults"],
srcs: [
+ ":TestCommonMockFunctions",
+ ":TestMockStackMetrics",
"hci/fuzz/acl_manager_fuzz_test.cc",
],
+ include_dirs: [
+ "packages/modules/Bluetooth/system",
+ ],
+ static_libs: [
+ "libbt-platform-protos-lite",
+ ],
fuzz_config: {
cc: ["android-bluetooth-security@google.com"],
componentid: 27441,
@@ -629,38 +534,3 @@ cc_benchmark {
"server_configurable_flags",
],
}
-
-// Generates binary schema data to be bundled and source file generated
-genrule {
- name: "BluetoothGeneratedDumpsysBinarySchema_bfbs",
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) $(in) ",
- srcs: [
- "dumpsys_data.fbs",
- "module_unittest.fbs",
- "os/wakelock_manager.fbs",
- ],
- out: [
- "dumpsys_data.bfbs",
- "wakelock_manager.bfbs",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysDataSchema_h",
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -o $(genDir) --cpp $(in) ",
- srcs: [
- "dumpsys_data.fbs",
- "module_unittest.fbs",
- "os/wakelock_manager.fbs",
- ],
- out: [
- "dumpsys_data_generated.h",
- "wakelock_manager_generated.h",
- ],
-}
diff --git a/system/gd/BUILD.gn b/system/gd/BUILD.gn
index 14d5044d68..2ee45fde74 100644
--- a/system/gd/BUILD.gn
+++ b/system/gd/BUILD.gn
@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import("//bt/system/gd/dumpsys/bundler/bundler.gni")
import("//bt/system/gd/packet/parser/packetgen.gni")
import("//common-mk/flatbuffer.gni")
@@ -47,8 +46,6 @@ config("rust_defaults") {
group("gd_default_deps") {
deps = [
"//bt/system:libbt-platform-protos-lite",
- "//bt/system/gd:BluetoothGeneratedDumpsysDataSchema_h",
- "//bt/system/gd/dumpsys:libbluetooth-dumpsys",
"//bt/system/pdl:BluetoothGeneratedPackets_h",
]
}
@@ -56,8 +53,6 @@ group("gd_default_deps") {
static_library("libbluetooth_gd") {
sources = [
"module.cc",
- "module_dumper.cc",
- "stack_manager.cc",
]
include_dirs = [ "." ]
@@ -65,31 +60,14 @@ static_library("libbluetooth_gd") {
deps = [
"//bt/system/gd/rust/topshim:libbluetooth_topshim",
"//bt/system/gd/common:BluetoothCommonSources",
- "//bt/system/gd/dumpsys:BluetoothDumpsysSources",
"//bt/system/gd/hal:BluetoothHalSources",
"//bt/system/gd/hal:BluetoothHalSources_hci_host",
"//bt/system/gd/hal:BluetoothHalSources_ranging_host",
+ "//bt/system/gd/hal:BluetoothHalSources_socket_host",
"//bt/system/gd/metrics:BluetoothMetricsSources",
"//bt/system/gd/neighbor:BluetoothNeighborSources",
- "//bt/system/gd/shim:BluetoothShimSources",
"//bt/system/gd/storage:BluetoothStorageSources",
"//bt/system/gd/sysprops:BluetoothSyspropsSources",
"//bt/system/pdl:BluetoothGeneratedPackets_h",
]
}
-
-flatbuffer("BluetoothGeneratedDumpsysDataSchema_h") {
- sources = [
- "dumpsys_data.fbs",
- "os/wakelock_manager.fbs",
- ]
-}
-
-bt_flatc_binary_schema("BluetoothGeneratedDumpsysBinarySchema_bfbs") {
- sources = [
- "dumpsys_data.fbs",
- "os/wakelock_manager.fbs",
- ]
-
- include_dir = "system/gd"
-}
diff --git a/system/gd/cert/change_waiter.py b/system/gd/cert/change_waiter.py
deleted file mode 100644
index 30a72f9671..0000000000
--- a/system/gd/cert/change_waiter.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import pyinotify
-import sys
-
-wm = pyinotify.WatchManager()
-mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY
-
-
-class EventHandler(pyinotify.ProcessEvent):
-
- def process_default(self, event):
- quit()
-
-
-handler = EventHandler()
-notifier = pyinotify.Notifier(wm, handler)
-wdd = wm.add_watch(sys.argv[1], mask, rec=True)
-
-notifier.loop()
diff --git a/system/gd/cert/gen_html_coverage.sh b/system/gd/cert/gen_html_coverage.sh
deleted file mode 100755
index bfb1edb3bf..0000000000
--- a/system/gd/cert/gen_html_coverage.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-pushd $ANDROID_BUILD_TOP
-
-llvm-cov show --format=html --summary-only --show-line-counts-or-regions --show-instantiation-summary --instr-profile=/tmp/logs/HostOnlyCert/latest/GdDevice_dut_backing_process_coverage.profdata --output-dir=/tmp/logs/HostOnlyCert/latest/GdDevice_dut_backing_process_coverage/ out/dist/bluetooth_venv/lib/python3.8/site-packages/bluetooth_stack_with_facade
-
-popd
-
-echo "point your browser to file:///tmp/logs/HostOnlyCert/latest/GdDevice_dut_backing_process_coverage/index.html"
-
diff --git a/system/gd/cert/irun b/system/gd/cert/irun
deleted file mode 100755
index 062f07f6cf..0000000000
--- a/system/gd/cert/irun
+++ /dev/null
@@ -1,10 +0,0 @@
-#! /bin/bash
-# interactive version of run
-
-trap "exit;" SIGINT SIGTERM
-
-while true
-do
- ${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/gd/cert/run "$@"
- python3 ${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/gd/cert/change_waiter.py ${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system
-done
diff --git a/system/gd/cert/run b/system/gd/cert/run
deleted file mode 100755
index 94708ff69c..0000000000
--- a/system/gd/cert/run
+++ /dev/null
@@ -1,495 +0,0 @@
-#! /bin/bash
-
-YELLOW="\033[1;33m"
-NOCOLOR="\033[0m"
-BLUE="\033[1;34m"
-RED="\033[1;91m"
-
-function happy_hedgehog {
- echo -e "\t${BLUE}"
- echo -e "\t ___------__"
- echo -e "\t |\__-- /\ _-"
- echo -e "\t |/_ __ -"
- echo -e "\t // \ / \ /__"
- echo -e "\t | 0 | 0 |__ --_ Gotta go fast!"
- echo -e "\t \\____-- __ \ ___-"
- echo -e "\t ( @ __/ / /_"
- echo -e "\t -_____--- --_"
- echo -e "\t // \ \\ ___-"
- echo -e "\t //|\__/ \\ \\"
- echo -e "\t \_-\_____/ \-\\"
- echo -e "\t // \\--\|"
- echo -e "\t ${RED}____${BLUE}// ||${RED}_"
- echo -e "\t${RED} /_____\ /___\\"
- echo -e "${NOCOLOR}"
-}
-
-function sad_hedgehog {
- echo -e "\t${BLUE}"
- echo -e "\t ___------__"
- echo -e "\t |\__-- /\ _-"
- echo -e "\t |/_ __ -"
- echo -e "\t // \ / \ /__"
- echo -e "\t | 0 | 0 |__ --_ Gotta go sllloowwww!"
- echo -e "\t \\____-- __ \ ___-"
- echo -e "\t ( @ __ / /_"
- echo -e "\t -_____--- --_"
- echo -e "\t // \ \\ ___-"
- echo -e "\t //|\__/ \\ \\"
- echo -e "\t \_-\_____/ \-\\"
- echo -e "\t // \\--\|"
- echo -e "\t ${RED} ____${BLUE}// ||${RED}_"
- echo -e "\t${RED} /_____\ /___\\"
- echo -e "{$NOCOLOR}"
-}
-
-PYTHON_BIN="python3.11"
-
-function check_environment {
- if [[ -z "${ANDROID_BUILD_TOP}" ]] || [[ -z "${ANDROID_HOST_OUT}" ]] ; then
- echo -e "${RED}ANDROID_BUILD_TOP${NOCOLOR} or ${RED}ANDROID_HOST_OUT${NOCOLOR} is not set for host run"
- echo -e "Navigate to android root and run:"
- echo -e "${YELLOW}"
- echo -e ". build/envsetup.sh"
- echo -e "lunch <fish>"
- echo -e "${NOCOLOR}"
- echo
- exit 1
- fi
- if ! [ -x "$(command -v ${PYTHON_BIN})" ] ; then
- echo -e "${RED}You must have ${PYTHON_BIN} installed${NOCOLOR}"
- exit 1
- fi
- ${PYTHON_BIN} -m venv -h > /dev/null
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}venv not available for ${PYTHON_BIN}${NOCOLOR}"
- exit 1
- fi
-}
-
-ASHMEM_OUT="/dev/shm/out"
-ASHMEM_DIST="${ASHMEM_OUT}/dist"
-ASHMEM_VENV="${ASHMEM_DIST}/bluetooth_venv"
-ASHMEM_GOTTA_GO_FAST="/dev/shm/gottagofast"
-ASHMEM_HOST_LOGS="${ASHMEM_GOTTA_GO_FAST}/logs"
-ASHMEM_OUT_TARGET="${ASHMEM_GOTTA_GO_FAST}/target"
-ASHMEM_SOONG="${ASHMEM_GOTTA_GO_FAST}/out/soong"
-CERT_HOST_LOGS="/tmp/logs/HostOnlyCert"
-CERT_DEVICE_LOGS="TODO: Add this"
-CERT_TEST_VENV=${ANDROID_BUILD_TOP}/out/dist/bluetooth_venv
-OUT_TARGET="${ANDROID_BUILD_TOP}/out/target"
-TEST_CONFIG="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry/tests/gd/host_config.yaml"
-TEST_FILTER="--presubmit"
-TEST_RUNNER="blueberry/tests/gd/gd_test_runner.py"
-CPP_BUILD_TARGET="bluetooth_stack_with_facade root-canal gd_hci_packets_python3_gen gd_smp_packets_python3_gen"
-RUST_BUILD_TARGET="bluetooth_with_facades root-canal bt_topshim_facade gd_hci_packets_python3_gen gd_smp_packets_python3_gen"
-BUILD_TARGET=$CPP_BUILD_TARGET
-
-CLEAN_VENV=false
-GOTTA_GO_FAST=false
-NUM_REPETITIONS="1"
-SKIP_SOONG_BUILD=false
-USE_ASHMEM_VENV=true
-VERBOSE_MODE=false
-DEVICE_TEST=false
-
-## Verify devices connected and valid
-DUT_SERIAL="DUT Not Set"
-DUT_ADB="DUT Not Set"
-DUT_NAME="DUT Not Set"
-
-# Used for position arguments needed for later
-POSITIONAL=()
-function parse_options {
- while [[ $# -gt 0 ]]
- do
- key="$1"
- case $key in
- # This will delete the existing venv before running the test
- # If you updated external libraries such as ACTS, you need to add this flag
- --clean)
- CLEAN_VENV=true
- shift # past argument
- ;;
- --help)
- echo
- echo -e "${YELLOW}Help menu${NOCOLOR}"
- echo -e "==================================="
- echo -e "${BLUE} --clean${NOCOLOR}"
- echo -e " Clean the virtul environment; use if ACTS has been updated."
- echo -e "${BLUE} --disable-ashmem-venv${NOCOLOR}"
- echo -e " Places the virtual environment on disk rather than in ashmem which is default."
- echo -e "${BLUE} --gotta-go-fast${NOCOLOR}"
- echo -e " Makes use of ashmem as best as possible for targeted speed increases."
- echo -e "${BLUE} --device${NOCOLOR}"
- echo -e " Run the test on the 2 real devices."
- echo -e "${BLUE} --topshim${NOCOLOR}"
- echo -e " Run Topshim combination tests using the default topshim config."
- echo -e "${BLUE} --rust${NOCOLOR}"
- echo -e " Run the test using the rust implementation on the 2 real devices."
- echo -e "${BLUE} --rhost${NOCOLOR}"
- echo -e " Run the test using the rust implementation on the host."
- echo -e "${BLUE} --repeat=<N>${NOCOLOR}"
- echo -e " Repeat the test sequence N (int) number of times."
- echo -e "${BLUE} --skip-soong-build${NOCOLOR}"
- echo -e " Skips building soong targets. Use when you are just modifying simple python files."
- echo -e "${BLUE} --test_config=<configfile>${NOCOLOR}"
- echo -e " Override default test configuration."
- echo -e "${BLUE} --verbose${NOCOLOR}"
- echo -e " Displays device logs and test logs to output."
- echo
- echo -e "Usage: $0 [--clean|--repeat=<N>|--test_config=<config>] [TestGroupName[.IndividualTestName]]"
- echo -e " ${YELLOW}e.g."
- echo -e " $0 --clean SecurityTest"
- echo -e " $0 --verbose SecurityTest:test_dut_initiated_display_only_display_only ${NOCOLOR}"
- echo
- shift
- exit 0
- ;;
- # This will cause the bluetooth_venv to NOT be created in ashmem
- # Using ashmem increases --clean build times by 40% (~21 seconds on my machine)
- --disable-ashmem-venv)
- USE_ASHMEM_VENV=false
- shift # past argument
- ;;
- --gotta-go-fast)
- GOTTA_GO_FAST=true
- shift # past argument
- ;;
- --device)
- DEVICE_TEST=true
- TEST_CONFIG="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry/tests/gd/devices_config.yaml"
- shift # past argument
- ;;
- # Repeat running the specified test cases by N times in one single setup
- --repeat=*)
- NUM_REPETITIONS="${key#*=}"
- shift # past argument
- ;;
- --skip-soong-build)
- SKIP_SOONG_BUILD=true
- shift
- ;;
- --test_config=*)
- TEST_CONFIG="${key#*=}"
- shift # past argument
- ;;
- --rust)
- BUILD_TARGET=$RUST_BUILD_TARGET
- export RUST_BACKTRACE=1
- TEST_CONFIG="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry/tests/gd/rust_devices_config.yaml"
- DEVICE_TEST=true
- shift # past argument
- ;;
- --rhost)
- export RUST_BACKTRACE=1
- BUILD_TARGET=$RUST_BUILD_TARGET
- TEST_CONFIG="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry/tests/gd/rust_host_config.yaml"
- shift # past argument
- ;;
- --topshim)
- TEST_CONFIG="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry/tests/topshim/topshim_host_config.yaml"
- TEST_RUNNER="blueberry/tests/topshim/topshim_test_runner.py"
- shift
- ;;
- # This will log everything to both log file and stdout
- --verbose)
- VERBOSE_MODE=true
- shift # past argument
- ;;
- --*) # unknown argument
- echo "$0: unrecognized argument '$1'"
- echo "Try '$0 --help' for more information"
- exit 1
- shift
- ;;
- *) # unknown option
- POSITIONAL+=("$1") # save it in an array for later
- shift # past argument
- ;;
- esac
- done
- set -- "${POSITIONAL[@]}" # restore positional parameters
-
- # Set the test filter
- if [[ -n "$1" ]] ; then
- TEST_FILTER="--tests $1"
- fi
-
- INSTALL_ARGS="--reuse-libraries"
- if [ "$CLEAN_VENV" == true ] ; then
- echo -e "${YELLOW}Cleaning up existing virtualenv${NOCOLOR}"
- rm -rf $CERT_TEST_VENV/*
- rm -rf $CERT_TEST_VENV
- mkdir -p ${CERT_TEST_VENV}
- INSTALL_ARGS=""
- else
- echo -e "${YELLOW}Try to reuse existing virtualenv at ${CERT_TEST_VENV}${NOCOLOR}"
- fi
-
-}
-
-function select_devices {
- if [ "$DEVICE_TEST" == true ] ; then
- RR="$(cat ${TEST_CONFIG}|grep \'CERT\\\|DUT\')"
- if [ "$RR" != "" ]; then
- DUT_SERIAL="$(menu-adb DUT)"
- DUT_ADB="adb -s ${DUT_SERIAL}"
- DUT_NAME="$(adb devices -l | grep -v "List of device" | grep ${DUT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)"
- CERT_SERIAL="$(menu-adb CERT)"
- CERT_ADB="adb -s ${CERT_SERIAL}"
- CERT_NAME="$(adb devices -l | grep -v "List of device" | grep ${CERT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)"
-
- if [ "${CERT_SERIAL}" == "${DUT_SERIAL}" ]; then
- echo
- echo -e "${RED}ERROR: CERT and DUT cannot be the same device, or you only have one device connected!${NOCOLOR}"
- echo
- exit 1
- fi
-
- ## Set android devices in config
- sed -i "s/'DUT'/'${DUT_SERIAL}'/g" ${TEST_CONFIG}
- sed -i "s/'CERT'/'${CERT_SERIAL}'/g" ${TEST_CONFIG}
- fi
- fi
-}
-
-function soong_build {
- if [ "$CLEAN_VENV" == true ] ; then
- $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --build-mode --"modules-in-a-dir" --dir="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system" dist $BUILD_TARGET -j $(nproc)
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Failed to build ${BUILD_TARGET}${NOCOLOR}"
- exit 1
- fi
- else
- $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --build-mode --"all-modules" --dir="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system" dist $BUILD_TARGET -j $(nproc)
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Failed to build ${BUILD_TARGET}${NOCOLOR}"
- exit 1
- fi
- fi
-}
-
-function setup_venv {
- # Make venv in memory, decreases --clean build times by 40%
- # Caveat is you lose the venv if the computer reboots
- if [ "${USE_ASHMEM_VENV}" == true ] ; then
- echo -e "${BLUE}Using ashmem virtual environment.${NOCOLOR}"
- if [[ ! -L ${CERT_TEST_VENV} ]] ; then
- echo -e "${BLUE}"
- echo -ne "Creating ashmem dist folder..."
- mkdir -p "${ASHMEM_VENV}"
- # Ensure the directory doesn't exist
- rm -rf "${CERT_TEST_VENV}"
- echo -e "Done"
- echo -ne "Sym linking ${ASHMEM_VENV} to ${CERT_TEST_VENV}..."
- ln -s "${ASHMEM_VENV}" "${CERT_TEST_VENV}"
- echo -e "Done"
- echo -e "${NOCOLOR}"
- fi
- else
- echo -e "${RED}Not using ashmem virtual environment.${NOCOLOR}"
- if [[ -L ${CERT_TEST_VENV} ]] ; then
- echo -e "${RED}"
- echo -en "Removing sym link from ${ASHMEM_VENV} to ${CERT_TEST_VENV}..."
- rm -rf ""${ASHMEM_VENV} "${CERT_TEST_VENV}"
- echo -e "Done"
- echo -en "Cleaning up memory..."
- rm -rf "${ASHMEM_VENV}"
- echo -e "Done"
- echo -e "${NOCOLOR}"
- fi
- fi
- ${PYTHON_BIN} -m venv --clear "${CERT_TEST_VENV}"
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Error setting up virtualenv${NOCOLOR}"
- exit 1
- fi
-
- unzip -o -q "${ANDROID_BUILD_TOP}/out/dist/bluetooth_cert_tests.zip" -d "${CERT_TEST_VENV}/sources"
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Error unzipping bluetooth_cert_tests.zip${NOCOLOR}"
- exit 1
- fi
-
- venv_common
-}
-
-function incremental_venv {
-#LINT.IfChange
- HOST_BIN="${ANDROID_BUILD_TOP}/out/host/linux-x86/bin"
- HOST_LIB="${ANDROID_BUILD_TOP}/out/host/linux-x86/lib64"
- DEST_DIR="${ANDROID_BUILD_TOP}/out/dist/bluetooth_venv/sources"
- DEST_LIB_DIR="${DEST_DIR}/lib64"
- cp {$HOST_BIN,$DEST_DIR}/bluetooth_stack_with_facade
- cp {$HOST_BIN,$DEST_DIR}/bluetooth_with_facades
- cp {$HOST_BIN,$DEST_DIR}/bt_topshim_facade
- cp {$HOST_BIN,$DEST_DIR}/root-canal
-
- cp {$HOST_LIB,$DEST_LIB_DIR}/libbase.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libbluetooth_gd.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libc++.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libchrome.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libcrypto-host.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libevent-host.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libgrpc++.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libgrpc_wrap.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/liblog.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libssl-host.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libz-host.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libprotobuf-cpp-full.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/libunwindstack.so
- cp {$HOST_LIB,$DEST_LIB_DIR}/liblzma.so
-
- i="${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/setup.py"
- cp {${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system,$DEST_DIR}${i#${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system}
- for i in `find ${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/blueberry -name "*.py" -type f`; do
- cp {${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system,$DEST_DIR}${i#${ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system}
- done
-#LINT.ThenChange(../../Android.mk)
-
- venv_common
-}
-
-function venv_common {
- $(echo "${CERT_TEST_VENV}/bin/python" "${CERT_TEST_VENV}/sources/setup.py" --quiet build --force "${INSTALL_ARGS}")
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Error building GD Python libraries${NOCOLOR}"
- echo -e "${YELLOW}NOTE:${NOCOLOR} To build external libraries the first time, please add --clean option."
- exit 1
- fi
-
- $(echo "${CERT_TEST_VENV}/bin/python" "${CERT_TEST_VENV}/sources/setup.py" --quiet install --skip-build --force "${INSTALL_ARGS}")
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Error installing GD Python libraries${NOCOLOR}"
- exit 1
- fi
-
-if [ "${VERBOSE_MODE}" == true ] ; then
- TEMP_CONFIG=/tmp/temp_mobly_config.yaml
- cat "${TEST_CONFIG}" | "${CERT_TEST_VENV}/bin/python" -c "
-import sys
-import yaml
-config = yaml.load(sys.stdin)
-config['verbose_mode'] = True
-print(yaml.dump(config))
- " > "${TEMP_CONFIG}"
- TEST_CONFIG="${TEMP_CONFIG}"
- if [[ $? -ne 0 ]] ; then
- echo -e "${RED}Setup failed as verbose mode is chosen but cannot be enabled${NOCOLOR}"
- exit 1
- fi
-fi
-}
-
-function gotta_go_fast {
- if [ "${GOTTA_GO_FAST}" == true ] ; then
- # Call here to explicitly note the flag is in use
- happy_hedgehog
- if [[ ! -L "${CERT_HOST_LOGS}" ]] ; then
- rm -rf "${CERT_HOST_LOGS}"
- mkdir -p "${ASHMEM_HOST_LOGS}"
- ln -s "${ASHMEM_HOST_LOGS}" "${CERT_HOST_LOGS}"
- fi
-
- if [[ ! -L "${OUT_TARGET}" ]] ; then
- rm -rf "${OUT_TARGET}"
- mkdir -p "${ASHMEM_OUT_TARGET}"
- ln -s "${ASHMEM_OUT_TARGET}" "${OUT_TARGET}"
- fi
- else
- if [[ -L "${CERT_HOST_LOGS}" ]] ; then
- # Call here so we don't spam anyone not using the flag
- sad_hedgehog
- rm -rf "${CERT_HOST_LOGS}"
- rm -rf "${ASHMEM_HOST_LOGS}"
- fi
-
- if [[ -L "${OUT_TARGET}" ]] ; then
- rm -rf "${OUT_TARGET}"
- rm -rf "${ASHMEM_OUT_TARGET}"
- fi
- fi
-}
-
-function run_tests {
- for n in $(seq "${NUM_REPETITIONS}"); do
- $(echo "${CERT_TEST_VENV}/bin/python" "${CERT_TEST_VENV}/sources/${TEST_RUNNER}" \
- "-c ${TEST_CONFIG}" "${TEST_FILTER}")
- done
-
- if [ "${CLEAN_VENV}" != true ] ; then
- echo -e "${YELLOW}NOTE:${NOCOLOR} Completed tests using existing external libraries in virtualenv."
- echo -e "${YELLOW}NOTE:${NOCOLOR} To update external libraries, please add --clean option."
- fi
-}
-
-function menu-adb() {
- TMP=$(adb devices -l | grep -v "List of device" | awk '{ print $1 }')
- # TODO(optedoblivion): If the device doesn't have a name (offline), it misnames them
- NTMP=$(adb devices -l | grep -v "List of device" | awk '{ print $6 }' | cut -d ':' -f 2)
- SERIALS=($TMP)
- DEVICES=($NTMP)
- LEN=${#SERIALS[@]}
- result=0
- if [ $LEN -lt 1 ]; then
- echo -e "${YELLOW}No devices connected!${NOCOLOR}"
- return 1
- fi
-
- if [ "$LEN" == "" ]; then
- LEN=0
- fi
-
- answer=0
-
- DEVICE_NAME="$1 device"
-
- if [ $LEN -gt 1 ]; then
- echo "+-------------------------------------------------+" 1>&2
- echo "| Choose a ${DEVICE_NAME}: " 1>&2
- echo "+-------------------------------------------------+" 1>&2
- echo "| |" 1>&2
- let fixed_len=$LEN-1
- for i in `seq 0 $fixed_len`;
- do
- serial=${SERIALS[i]}
- device=${DEVICES[i]}
- echo "| $i) $serial $device" 1>&2
- ## TODO[MSB]: Find character count, fill with space and ending box wall
- done
- echo "| |" 1>&2
- echo "+-------------------------------------------------+" 1>&2
- echo 1>&2
- echo -n "Index number: " 1>&2
- read answer
- fi
-
- if [ $answer -ge $LEN ]; then
- echo
- echo "Please choose a correct index!" 1>&2
- echo
- return 1
- fi
-
- SERIAL=${SERIALS[$answer]}
- echo $SERIAL
-}
-
-function main {
- check_environment
- parse_options $@
- select_devices
- if [[ "${SKIP_SOONG_BUILD}" != true ]] ; then
- soong_build
- fi
- if [ "$CLEAN_VENV" == true ] ; then
- setup_venv
- else
- incremental_venv
- fi
- gotta_go_fast
- run_tests
-}
-
-main $@
diff --git a/system/gd/cert/set_up_and_run_device_cert.sh b/system/gd/cert/set_up_and_run_device_cert.sh
deleted file mode 100755
index 60e9ce00c5..0000000000
--- a/system/gd/cert/set_up_and_run_device_cert.sh
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/bin/bash
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-
-function menu-adb() {
- TMP=$(adb devices -l | grep -v "List of device" | awk '{ print $1 }')
- # TODO(optedoblivion): If the device doesn't have a name (offline), it misnames them
- NTMP=$(adb devices -l | grep -v "List of device" | awk '{ print $6 }' | cut -d ':' -f 2)
- SERIALS=($TMP)
- DEVICES=($NTMP)
- LEN=${#SERIALS[@]}
- result=0
- if [ $LEN -lt 1 ]; then
- echo "No devices connected!"
- return 1
- fi
-
- if [ "$LEN" == "" ]; then
- LEN=0
- fi
-
- answer=0
-
- DEVICE_NAME="$1 device"
-
- if [ $LEN -gt 1 ]; then
- echo "+-------------------------------------------------+" 1>&2
- echo "| Choose a ${DEVICE_NAME}: " 1>&2
- echo "+-------------------------------------------------+" 1>&2
- echo "| |" 1>&2
- let fixed_len=$LEN-1
- for i in `seq 0 $fixed_len`;
- do
- serial=${SERIALS[i]}
- device=${DEVICES[i]}
- echo "| $i) $serial $device" 1>&2
- ## TODO[MSB]: Find character count, fill with space and ending box wall
- done
- echo "| |" 1>&2
- echo "+-------------------------------------------------+" 1>&2
- echo 1>&2
- echo -n "Index number: " 1>&2
- read answer
- fi
-
- if [ $answer -ge $LEN ]; then
- echo
- echo "Please choose a correct index!" 1>&2
- echo
- return 1
- fi
-
- SERIAL=${SERIALS[$answer]}
- echo $SERIAL
-}
-
-function UpFind {
- while [[ $PWD != / ]] ; do
- rc=$(find "$PWD" -maxdepth 1 "$@")
- if [ -n "$rc" ]; then
- echo $(dirname "$rc")
- return
- fi
- cd ..
- done
-}
-
-
-function get-android-root() {
- android_root=$(UpFind -name dalvik -type d)
- if [[ -z $android_root ]] ; then
- echo
- echo "Needs to be ran in the android tree"
- echo
- return 1
- fi
- echo "${android_root}"
-}
-
-function banner() {
- echo
- echo "GD On Device Cert Test"
- echo
-}
-
-## Main
-banner
-
-DRY_RUN=""
-DO_BUILD=0
-echo "$@"
-if [ $# -gt 0 ]; then
- for var in "$@"
- do
- if [ "$var" == "-h" ]; then
- echo
- echo "Usage: $0 [-h|-d]"
- echo
- echo "Available Options:"
- echo "=================="
- echo " -h | Help(this) Menu"
- echo " -d | Dry run; just prints commands"
- echo
- return 0
- elif [ "$var" == "-d" ]; then
- DRY_RUN="echo"
- elif [ "$var" == "-b" ]; then
- DO_BUILD=1
- fi
- done
-fi
-
-## Verify devices connected and sane
-DUT_SERIAL="$(menu-adb DUT)"
-DUT_ADB="adb -s ${DUT_SERIAL}"
-DUT_NAME="$(adb devices -l | grep -v "List of device" | grep ${DUT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)"
-
-CERT_SERIAL="$(menu-adb CERT)"
-CERT_ADB="adb -s ${CERT_SERIAL}"
-CERT_NAME="$(adb devices -l | grep -v "List of device" | grep ${CERT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)"
-
-if [ "${CERT_SERIAL}" == "${DUT_SERIAL}" ]; then
- echo
- echo "ERROR: CERT and DUT cannot be the same device, or you only have one device connected!"
- echo
- return 1
-fi
-
-## Start builds
-if [ $DO_BUILD == 1 ]; then
- $DRY_RUN cd $(get-android-root)
- $DRY_RUN . build/envsetup.sh
- #DUT
- $DRY_RUN lunch $DUT_NAME
- $DRY_RUN cd $(get-android-root)/packages/modules/Bluetooth/system/gd
- $DRY_RUN mma -j `cat /proc/cpuinfo | grep core | wc -l`
- $DRY_RUN cd $(get-android-root)
- # CERT
- $DRY_RUN lunch $CERT_NAME
- $DRY_RUN cd $(get-android-root)/packages/modules/Bluetooth/system/gd
- $DRY_RUN mma -j `cat /proc/cpuinfo | grep core | wc -l`
- $DRY_RUN cd $(get-android-root)
-fi
-
-## Set android devices in config
-pushd .
-cd "${DIR}"
-# Reset in case user chooses different item in menu
-git checkout devices_config.json
-popd
-$DRY_RUN sed -i "s/\"DUT\"/\"${DUT_SERIAL}\"/g" ${DIR}/devices_config.json
-$DRY_RUN sed -i "s/\"CERT\"/\"${CERT_SERIAL}\"/g" ${DIR}/devices_config.json
-
-## ACTS
-#$DRY_RUN source $(get-android-root)/packages/modules/Bluetooth/system/gd/cert/set_up_acts.sh
-
-## Start test
-$DRY_RUN $(get-android-root)/packages/modules/Bluetooth/system/gd/cert/run --device
diff --git a/system/gd/common/audit_log.cc b/system/gd/common/audit_log.cc
index 5897c70aac..36cee3c801 100644
--- a/system/gd/common/audit_log.cc
+++ b/system/gd/common/audit_log.cc
@@ -42,10 +42,9 @@ void LogConnectionAdminAuditEvent([[maybe_unused]] const char* action,
#if defined(__ANDROID__) && !defined(FUZZ_TARGET)
android_log_event_list(SEC_TAG_BLUETOOTH_CONNECTION)
- << ADDRESS_TO_LOGGABLE_CSTR(address)
- << /* success */ int32_t(status == hci::ErrorCode::SUCCESS)
- << common::StringFormat("%s: %s", action, ErrorCodeText(status).c_str()).c_str()
- << LOG_ID_SECURITY;
+ << address.ToRedactedStringForLogging()
+ << /* success */ int32_t(status == hci::ErrorCode::SUCCESS) << action << ": "
+ << ErrorCodeText(status) << LOG_ID_SECURITY;
#endif /* defined(__ANDROID__) && !defined (FUZZ_TARGET) */
}
diff --git a/system/gd/common/interfaces/ILoggable.h b/system/gd/common/interfaces/ILoggable.h
deleted file mode 100644
index 0a0899511c..0000000000
--- a/system/gd/common/interfaces/ILoggable.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2022 Google, Inc.
- *
- * 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 <string>
-
-namespace bluetooth {
-namespace common {
-
-class ILoggable {
-public:
- // the interface for
- // converting an object to a string for feeding to loggers
- // e.g.. logcat
- virtual std::string ToStringForLogging() const = 0;
- virtual ~ILoggable() = default;
-};
-
-class IRedactableLoggable : public ILoggable {
-public:
- // the interface for
- // converting an object to a string with sensitive info redacted
- // to avoid violating privacy
- virtual std::string ToRedactedStringForLogging() const = 0;
- virtual ~IRedactableLoggable() = default;
-};
-
-} // namespace common
-} // namespace bluetooth
diff --git a/system/gd/dumpsys/Android.bp b/system/gd/dumpsys/Android.bp
deleted file mode 100644
index 84074824ac..0000000000
--- a/system/gd/dumpsys/Android.bp
+++ /dev/null
@@ -1,212 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_bt_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_bt_license"],
-}
-
-filegroup {
- name: "BluetoothDumpsysSources",
- srcs: [
- "filter.cc",
- "internal/filter_internal.cc",
- "reflection_schema.cc",
- ],
-}
-
-filegroup {
- name: "BluetoothDumpsysTestSources",
- srcs: [
- "filter_test.cc",
- "internal/filter_internal_test.cc",
- "reflection_schema_test.cc",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysTestData_h",
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) --cpp $(in) ",
- srcs: [
- "test_data/bar.fbs",
- "test_data/baz.fbs",
- "test_data/foo.fbs",
- "test_data/qux.fbs",
- "test_data/root.fbs",
- ],
- out: [
- "bar_generated.h",
- "baz_generated.h",
- "foo_generated.h",
- "qux_generated.h",
- "root_generated.h",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysTestData_bfbs",
- visibility: ["//visibility:private"],
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) --cpp $(in) ",
- srcs: [
- "test_data/bar.fbs",
- "test_data/baz.fbs",
- "test_data/foo.fbs",
- "test_data/qux.fbs",
- "test_data/root.fbs",
- ],
- out: [
- "bar.bfbs",
- "baz.bfbs",
- "foo.bfbs",
- "qux.bfbs",
- "root.bfbs",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysTestSchema_cc",
- visibility: ["//visibility:private"],
- tools: [
- "bluetooth_flatbuffer_bundler",
- ],
- cmd: "$(location bluetooth_flatbuffer_bundler) -w -m bluetooth.DumpsysData -f dumpsys_module_schema_data -n testing -g $(genDir) $(locations :BluetoothGeneratedDumpsysBinarySchema_bfbs)",
- srcs: [
- ":BluetoothGeneratedDumpsysBinarySchema_bfbs",
- ],
- out: [
- "dumpsys_module_schema_data.cc",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysBundledSchema_cc",
- visibility: ["//visibility:private"],
- tools: [
- "bluetooth_flatbuffer_bundler",
- ],
- cmd: "$(location bluetooth_flatbuffer_bundler) -w -m bluetooth.DumpsysData -f generated_dumpsys_bundled_schema -n bluetooth::dumpsys -g $(genDir) $(locations :BluetoothGeneratedDumpsysBinarySchema_bfbs)",
- srcs: [
- ":BluetoothGeneratedDumpsysBinarySchema_bfbs",
- ],
- out: [
- "generated_dumpsys_bundled_schema.cc",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysBundledTestSchema_cc",
- visibility: ["//visibility:private"],
- tools: [
- "bluetooth_flatbuffer_bundler",
- ],
- cmd: "$(location bluetooth_flatbuffer_bundler) -w -m testing.DumpsysTestDataRoot -f generated_dumpsys_bundled_test_schema -n testing -g $(genDir) $(locations :BluetoothGeneratedDumpsysTestData_bfbs)",
- srcs: [
- ":BluetoothGeneratedDumpsysTestData_bfbs",
- ],
- out: [
- "generated_dumpsys_bundled_test_schema.cc",
- ],
-}
-
-genrule {
- name: "BluetoothFlatbufferTestData_h",
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) --cpp $(in) ",
- srcs: [
- "bluetooth_flatbuffer_test.fbs",
- ],
- out: [
- "bluetooth_flatbuffer_test.bfbs",
- "bluetooth_flatbuffer_test_generated.h",
- ],
-}
-
-genrule {
- name: "BluetoothGeneratedDumpsysInternalTestData_h",
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) --cpp -o $(genDir)/dumpsys/internal/test_data $(in)",
- srcs: [
- "internal/test_data/float.fbs",
- "internal/test_data/integer.fbs",
- "internal/test_data/string.fbs",
- "internal/test_data/struct.fbs",
- ],
- out: [
- "dumpsys/internal/test_data/float_generated.h",
- "dumpsys/internal/test_data/integer_generated.h",
- "dumpsys/internal/test_data/string_generated.h",
- "dumpsys/internal/test_data/struct_generated.h",
- ],
-}
-
-cc_library {
- name: "libbluetooth-dumpsys",
- host_supported: true,
- defaults: [
- "gd_defaults",
- ],
- generated_sources: [
- "BluetoothGeneratedDumpsysBundledSchema_cc",
- ],
- apex_available: [
- "com.android.btservices",
- ],
- min_sdk_version: "30",
-}
-
-cc_library {
- name: "libbluetooth-dumpsys-test",
- host_supported: true,
- defaults: [
- "gd_defaults",
- ],
- generated_sources: [
- "BluetoothGeneratedDumpsysBundledTestSchema_cc",
- ],
-}
-
-cc_library {
- name: "libbluetooth-dumpsys-unittest",
- host_supported: true,
- defaults: [
- "gd_defaults",
- ],
- generated_headers: [
- "BluetoothGeneratedDumpsysTestSchema_cc",
- ],
-}
-
-cc_test {
- name: "bluetooth_flatbuffer_tests",
- test_suites: ["general-tests"],
- defaults: [
- "bluetooth_cflags",
- "mts_defaults",
- ],
- host_supported: true,
- test_options: {
- unit_test: true,
- },
- static_libs: [
- "libflatbuffers-cpp",
- "libgmock",
- ],
- srcs: [
- "bluetooth_flatbuffer_test.cc",
- ],
- generated_headers: [
- "BluetoothFlatbufferTestData_h",
- ],
- min_sdk_version: "30",
-}
diff --git a/system/gd/dumpsys/BUILD.gn b/system/gd/dumpsys/BUILD.gn
deleted file mode 100644
index 327089c2ed..0000000000
--- a/system/gd/dumpsys/BUILD.gn
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# Copyright 2021 Google, Inc.
-#
-# 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.
-
-import("//bt/system/gd/dumpsys/bundler/bundler.gni")
-
-source_set("BluetoothDumpsysSources") {
- sources = [
- "filter.cc",
- "internal/filter_internal.cc",
- "reflection_schema.cc",
- ]
-
- cflags_cc = [ "-Wno-enum-compare-switch" ]
-
- configs += [
- "//bt/system/gd:gd_defaults",
- "//bt/system/log:log_defaults",
- ]
- deps = [ "//bt/system/gd:gd_default_deps" ]
-}
-
-bt_flatc_bundler("libbluetooth-dumpsys") {
- root_name = "bluetooth.DumpsysData"
- filename = "generated_dumpsys_bundled_schema"
- namespace = "bluetooth::dumpsys"
- deps = [ "//bt/system/gd:BluetoothGeneratedDumpsysBinarySchema_bfbs" ]
- configs = [
- "//bt/system/gd:gd_defaults",
- "//bt/system/log:log_defaults",
- ]
-}
diff --git a/system/gd/dumpsys/bluetooth_flatbuffer_test.cc b/system/gd/dumpsys/bluetooth_flatbuffer_test.cc
deleted file mode 100644
index 7c77e1075d..0000000000
--- a/system/gd/dumpsys/bluetooth_flatbuffer_test.cc
+++ /dev/null
@@ -1,71 +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 <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "bluetooth_flatbuffer_test_generated.h"
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-#include "flatbuffers/util.h"
-
-namespace bluetooth {
-namespace dumpsys {
-
-class BluetoothFlatbufferTest : public ::testing::Test {
-protected:
- void SetUp() override {}
-
- void TearDown() override {}
-};
-
-TEST_F(BluetoothFlatbufferTest, precondition) {}
-
-TEST_F(BluetoothFlatbufferTest, BuilderTest) {
- flatbuffers::FlatBufferBuilder builder(1024);
- auto string_private = builder.CreateString("String private");
- auto string_opaque = builder.CreateString("String opaque");
- auto string_anonymized = builder.CreateString("String anonymized");
- auto string_any = builder.CreateString("String any");
-
- TestTableBuilder table_builder(builder);
- table_builder.add_string_private(string_private);
- table_builder.add_string_opaque(string_opaque);
- table_builder.add_string_anonymized(string_anonymized);
- table_builder.add_string_any(string_any);
-
- table_builder.add_int_private(123);
- table_builder.add_int_opaque(456);
- table_builder.add_int_anonymized(789);
- table_builder.add_int_any(0xabc);
-
- builder.Finish(table_builder.Finish());
-
- const TestTable* test_table = GetTestTable(builder.GetBufferPointer());
-
- ASSERT_EQ("String private", test_table->string_private()->str());
- ASSERT_EQ("String opaque", test_table->string_opaque()->str());
- ASSERT_EQ("String anonymized", test_table->string_anonymized()->str());
- ASSERT_EQ("String any", test_table->string_any()->str());
-
- ASSERT_EQ(123, test_table->int_private());
- ASSERT_EQ(456, test_table->int_opaque());
- ASSERT_EQ(789, test_table->int_anonymized());
- ASSERT_EQ(0xabc, test_table->int_any());
-}
-
-} // namespace dumpsys
-} // namespace bluetooth
diff --git a/system/gd/dumpsys/bluetooth_flatbuffer_test.fbs b/system/gd/dumpsys/bluetooth_flatbuffer_test.fbs
deleted file mode 100644
index f449813620..0000000000
--- a/system/gd/dumpsys/bluetooth_flatbuffer_test.fbs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Bluetooth module test schema
-
-attribute "privacy";
-
-table TestTable {
- string_private:string; // no privacy attribute implies private
- string_opaque:string (privacy:"Opaque");
- string_anonymized:string (privacy:"Anonymized");
- string_any:string (privacy:"Any");
-
- int_private:int32 (privacy:"Private"); // Explicitly private
- int_opaque:int32 (privacy:"Opaque");
- int_anonymized:int32 (privacy:"Anonymized");
- int_any:int32 (privacy:"Any");
-}
-
-root_type TestTable;
diff --git a/system/gd/dumpsys/bundler/Android.bp b/system/gd/dumpsys/bundler/Android.bp
deleted file mode 100644
index 301346ec6c..0000000000
--- a/system/gd/dumpsys/bundler/Android.bp
+++ /dev/null
@@ -1,91 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_bt_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_bt_license"],
-}
-
-filegroup {
- name: "BluetoothFlatbufferBundlerSources",
- visibility: ["//visibility:private"],
- srcs: [
- "bundler.cc",
- "main.cc",
- ],
-}
-
-filegroup {
- name: "BluetoothFlatbufferBundlerTestSources",
- visibility: ["//visibility:private"],
- srcs: [
- "bundler.cc",
- "test.cc",
- ],
-}
-
-// Flatbuffer bundler schema that wraps the bundled binary module schema
-genrule {
- name: "BluetoothGeneratedBundlerSchema_h_bfbs",
- visibility: [
- "//packages/modules/Bluetooth/system/bta",
- "//packages/modules/Bluetooth/system/btif",
- "//packages/modules/Bluetooth/system/btm",
- "//packages/modules/Bluetooth/system/gd",
- "//packages/modules/Bluetooth/system/main",
- "//packages/modules/Bluetooth/system/rust",
- "//packages/modules/Bluetooth/system/stack",
- ],
- tools: [
- "flatc",
- ],
- cmd: "$(location flatc) -I packages/modules/Bluetooth/system/gd -b --schema -o $(genDir) --cpp $(in) ",
- srcs: [
- "bundler_schema.fbs",
- ],
- out: [
- "bundler_schema.bfbs",
- "bundler_schema_generated.h",
- ],
-}
-
-cc_defaults {
- name: "bluetooth_flatbuffer_bundler_defaults",
- defaults: ["bluetooth_cflags"],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- ],
- sanitize: {
- misc_undefined: ["bounds"],
- },
- static_libs: [
- "libflatbuffers-cpp",
- ],
-}
-
-cc_binary_host {
- name: "bluetooth_flatbuffer_bundler",
- srcs: [
- ":BluetoothFlatbufferBundlerSources",
- ],
- defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
- ],
-}
-
-cc_test_host {
- name: "bluetooth_flatbuffer_bundler_test",
- srcs: [
- ":BluetoothFlatbufferBundlerTestSources",
- ],
- defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
- ],
- data: [
- "test.bfbs",
- ],
- test_options: {
- unit_test: true,
- },
-}
diff --git a/system/gd/dumpsys/bundler/BUILD.gn b/system/gd/dumpsys/bundler/BUILD.gn
deleted file mode 100644
index 324afbb4f1..0000000000
--- a/system/gd/dumpsys/bundler/BUILD.gn
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Copyright 2021 Google, Inc.
-#
-# 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.
-
-import("//bt/system/gd/dumpsys/bundler/bundler.gni")
-import("//common-mk/flatbuffer.gni")
-
-bt_flatc_binary_schema("BluetoothGeneratedBundlerSchema_h_bfbs") {
- sources = [ "bundler_schema.fbs" ]
- include_dir = "bt/system/gd"
- gen_header = true
-}
-
-#
-# The remaining rules are for building on the host
-#
-
-config("bundler_defaults") {
- cflags = [ "-fPIC" ]
-
- cflags_cc = [
- "-std=c++17",
- "-Wno-unused-variable",
- "-Wno-poison-system-directories",
- ]
-}
-
-executable("bluetooth_flatbuffer_bundler") {
- sources = [
- "bundler.cc",
- "main.cc",
- ]
-
- libs = [ "flatbuffers" ]
-
- deps = [ ":BluetoothGeneratedBundlerSchema_h_bfbs" ]
-
- configs += [ ":bundler_defaults" ]
-}
diff --git a/system/gd/dumpsys/bundler/bundler.cc b/system/gd/dumpsys/bundler/bundler.cc
deleted file mode 100644
index 72097ac101..0000000000
--- a/system/gd/dumpsys/bundler/bundler.cc
+++ /dev/null
@@ -1,322 +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 "bundler.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <cassert>
-#include <list>
-#include <map>
-#include <vector>
-
-#include "bundler_schema_generated.h"
-#include "flatbuffers/idl.h"
-#include "flatbuffers/util.h"
-
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
-using namespace bluetooth;
-using namespace dumpsys;
-
-struct Opts opts;
-
-/**
- * Load a binary schema from persistent store using flatbuffer API.
- *
- * @param filename; Name of file to open and read.
- * @param binary_schema: Backing store for flatbuffer binary schema data.
- *
- * @return: True if operation successful, false otherwise.
- */
-bool LoadBinarySchema(const char* filename, std::string* binary_schema) {
- assert(filename != nullptr);
- assert(binary_schema != nullptr);
- if (!flatbuffers::LoadFile(filename, helper::AsBinaryFile, binary_schema)) {
- fprintf(stderr, "Unable to open binary flatbuffer schema file:%s\n", filename);
- return false;
- };
- return true;
-}
-
-/**
- * Verify a binary schema using flatbuffer API.
- *
- * @param schema: Raw binary schema to verify
- *
- * @return: True if operation successful, false otherwise.
- */
-bool VerifyBinarySchema(const std::vector<uint8_t>& raw_schema) {
- flatbuffers::Verifier verifier(raw_schema.data(), raw_schema.size());
- if (!reflection::VerifySchemaBuffer(verifier)) {
- return false;
- }
- return true;
-}
-
-/**
- * Bundle a set of binary flatbuffer schema into the bundler database.
- *
- * @param builder; Flatbuffer builder
- * @param filenames: Set of filenames to include in bundle
- * @param vector_map: Filename to filedata mapping
- *
- * @return: True if operation successful, false otherwise.
- */
-bool CreateBinarySchemaBundle(flatbuffers::FlatBufferBuilder* builder,
- const std::vector<std::string>& filenames,
- std::vector<flatbuffers::Offset<BundledSchemaMap>>* vector_map,
- std::list<std::string>* bundled_names) {
- assert(builder != nullptr);
- assert(vector_map != nullptr);
- assert(bundled_names != nullptr);
-
- for (auto filename : filenames) {
- std::string string_schema;
- if (!LoadBinarySchema(filename.c_str(), &string_schema)) {
- fprintf(stderr, "Unable to load binary schema from filename:%s\n", filename.c_str());
- return false;
- }
- std::vector<uint8_t> raw_schema(string_schema.begin(), string_schema.end());
- if (!VerifyBinarySchema(raw_schema)) {
- fprintf(stderr, "Failed verification on binary schema filename:%s\n", filename.c_str());
- return false;
- }
-
- const reflection::Schema* schema = reflection::GetSchema(raw_schema.data());
- if (schema->root_table() == nullptr) {
- fprintf(stderr, "Unable to find root table for binary flatbuffer schema:%s\n",
- filename.c_str());
- return false;
- }
-
- bundled_names->push_back(schema->root_table()->name()->str());
- auto name = builder->CreateString(schema->root_table()->name()->str());
- auto data = builder->CreateVector<uint8_t>(raw_schema.data(), raw_schema.size());
- vector_map->push_back(CreateBundledSchemaMap(*builder, name, data));
-
- if (opts.verbose) {
- fprintf(stdout, "Bundled binary schema file:%s\n", schema->root_table()->name()->c_str());
- }
- }
- return true;
-}
-
-/**
- * Write generated header file containing the bundled binary schema
- * data and meta data
- *
- * @param data: Source file data.
- * @param data_len: length of data
- */
-void WriteHeaderFile(FILE* fp, const uint8_t* data, size_t data_len) {
- assert(fp != nullptr);
- std::string delim(kDefaultNamespaceDelim);
- std::string ns_string(opts.ns_name);
- std::vector<std::string> namespaces;
-
- size_t start = 0;
- size_t end = ns_string.find(delim);
- while (end != std::string::npos) {
- namespaces.push_back(ns_string.substr(start, end - start));
- start = end + delim.size();
- end = ns_string.find(delim, start);
- }
- if (start != 0 && start != std::string::npos) {
- namespaces.push_back(ns_string.substr(start));
- } else if (!ns_string.empty()) {
- namespaces.push_back(ns_string);
- }
-
- std::string namespace_prefix;
- for (const auto& name : namespaces) {
- namespace_prefix += (name + '_');
- }
-
- fprintf(fp,
- "// Generated file by bluetooth_flatbuffer bundler\n"
- "#include <string>\n");
- for_each(namespaces.begin(), namespaces.end(),
- [fp](const std::string& s) { fprintf(fp, "namespace %s {\n", s.c_str()); });
- fprintf(fp, "extern const std::string& GetBundledSchemaData();\n");
- fprintf(fp, "const unsigned char %sdata_[%zu] = {\n", namespace_prefix.c_str(), data_len);
-
- for (size_t i = 0; i < data_len; i++) {
- fprintf(fp, " 0x%02x", data[i]);
- if (i != data_len - 1) {
- fprintf(fp, ",");
- }
- if ((i + 1) % 16 == 0) {
- fprintf(fp, "\n");
- }
- }
- fprintf(fp, " };\n");
- fprintf(fp, "const std::string %sstring_data_(%sdata_, %sdata_ + sizeof(%sdata_));\n",
- namespace_prefix.c_str(), namespace_prefix.c_str(), namespace_prefix.c_str(),
- namespace_prefix.c_str());
- fprintf(fp, "const std::string& GetBundledSchemaData() { return %sstring_data_; }\n",
- namespace_prefix.c_str());
-
- for_each(namespaces.crbegin(), namespaces.crend(),
- [fp](const std::string& s) { fprintf(fp, "} // namespace %s\n", s.c_str()); });
-}
-
-int ReadBundledSchema() {
- const char* filename = opts.filename;
- assert(filename != nullptr);
-
- std::string flatfile_data;
- if (!flatbuffers::LoadFile(filename, helper::AsBinaryFile, &flatfile_data)) {
- fprintf(stderr, "Unable to load schema data file:%s\n", filename);
- return -5;
- }
-
- auto bundle_schema = flatbuffers::GetRoot<BundledSchema>(flatfile_data.c_str());
- const flatbuffers::Vector<flatbuffers::Offset<BundledSchemaMap>>* map = bundle_schema->map();
-
- fprintf(stdout, "Bundle schema title:%s\n", bundle_schema->title()->c_str());
- fprintf(stdout, "Bundle schema root_name:%s\n", bundle_schema->root_name()->c_str());
- int cnt = 0;
- for (auto it = map->cbegin(); it != map->cend(); ++it, cnt++) {
- fprintf(stdout, " %d name:%s schema:%s\n", cnt, it->name()->c_str(), "schema");
- }
- return EXIT_SUCCESS;
-}
-
-int WriteBundledSchema() {
- const char* filename = opts.filename;
- assert(filename != nullptr);
-
- const char* main_root_name = opts.main_root_name;
- if (main_root_name == nullptr) {
- fprintf(stderr, "Must specify the name of the main root name for this bundle\n");
- return EXIT_FAILURE;
- }
-
- std::vector<std::string> bfbs_filenames;
- for (int i = 0; i < opts.arg.c; i++) {
- bfbs_filenames.push_back(std::string(opts.arg.v[i]));
- }
- if (bfbs_filenames.empty()) {
- fprintf(stderr, "No bfbs files are specified to bundle\n");
- return EXIT_FAILURE;
- }
-
- flatbuffers::FlatBufferBuilder builder(1024);
-
- std::list<std::string> bundled_names;
- std::vector<flatbuffers::Offset<BundledSchemaMap>> vector_map;
- if (!CreateBinarySchemaBundle(&builder, bfbs_filenames, &vector_map, &bundled_names)) {
- fprintf(stderr, "Unable to bundle schema bfbs files\n");
- return EXIT_FAILURE;
- }
-
- if (std::find(bundled_names.begin(), bundled_names.end(), main_root_name) ==
- bundled_names.end()) {
- fprintf(stderr, "The main root name must match one of the bundled schema names\n");
- fprintf(stderr, " main root name:%s\n", main_root_name);
- for (auto name : bundled_names) {
- fprintf(stderr, " bundled schema name:%s\n", name.c_str());
- }
- return EXIT_FAILURE;
- }
-
- const char* title = opts.title;
- auto schema_offset = CreateBundledSchemaDirect(builder, title, main_root_name, &vector_map);
- builder.Finish(schema_offset);
-
- std::string final_filename(opts.gen);
- final_filename.append("/");
- final_filename.append(filename);
- if (!flatbuffers::SaveFile(final_filename.c_str(), (const char*)builder.GetBufferPointer(),
- builder.GetSize(), helper::AsBinaryFile)) {
- fprintf(stderr, "Unable to save file:%s\n", final_filename.c_str());
- return EXIT_FAILURE;
- }
-
- std::string header(opts.gen);
- header += ("/" + std::string(opts.filename) + ".cc");
- FILE* fp = fopen(header.c_str(), "w+");
- if (fp == nullptr) {
- fprintf(stdout, "Unable to open for writing header file:%s\n", header.c_str());
- return EXIT_FAILURE;
- }
- WriteHeaderFile(fp, builder.GetBufferPointer(), builder.GetSize());
- fclose(fp);
- return EXIT_SUCCESS;
-}
-
-int Usage(int /*argc*/, char** argv) {
- fprintf(stderr,
- "Usage: %s [-r | -w] [-f <filename>] [-g <gen_out_path>] [-n <namespace> ] [-v] -m "
- "<main_root_name> <file.bfbs "
- "...>\n",
- argv[0]);
- fprintf(stderr, " -r|-w : Read or write a dumpsys file\n");
- fprintf(stderr, " -f : Filename bundled schema to read or write (default:%s)\n",
- kDefaultBundleDataFile);
- fprintf(stderr, " -g : Generated file output path\n");
- fprintf(stderr, " -n : Namespace to embed binary output bundle data source\n");
- fprintf(stderr, " -m : Name of the main root of this bundle\n");
- fprintf(stderr, " -v : Verbose printing mode\n");
- return EXIT_FAILURE;
-}
-
-void ParseArgs(int argc, char** argv) {
- int opt;
- int parsed_cnt = 1;
- while ((opt = getopt(argc, argv, "f:g:m:n:rt:vw")) != -1) {
- parsed_cnt++;
- switch (opt) {
- case 'f':
- opts.filename = optarg;
- parsed_cnt++;
- break;
- case 'g':
- opts.gen = optarg;
- parsed_cnt++;
- break;
- case 'm':
- opts.main_root_name = optarg;
- parsed_cnt++;
- break;
- case 'n':
- opts.ns_name = optarg;
- parsed_cnt++;
- break;
- case 'r':
- opts.read = true;
- break;
- case 'w':
- opts.write = true;
- break;
- case 't':
- opts.title = optarg;
- parsed_cnt++;
- break;
- case 'v':
- opts.verbose = true;
- break;
- default:
- exit(Usage(argc, argv));
- break;
- }
- }
- opts.arg.c = argc - parsed_cnt;
- opts.arg.v = &argv[parsed_cnt];
-}
diff --git a/system/gd/dumpsys/bundler/bundler.h b/system/gd/dumpsys/bundler/bundler.h
deleted file mode 100644
index 9dc4b243d2..0000000000
--- a/system/gd/dumpsys/bundler/bundler.h
+++ /dev/null
@@ -1,71 +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.
- */
-#pragma once
-
-namespace {
-constexpr char kDefaultBundleDataFile[] = "bundle_bfbs.bin";
-constexpr char kDefaultGeneratedOutputPath[] = ".";
-constexpr char kDefaultNamespace[] = "";
-constexpr char kDefaultNamespaceDelim[] = "::";
-constexpr char kDefaultTitle[] = "Bundled schema tables";
-} // namespace
-
-struct Opts {
- bool verbose{false};
- bool read{false};
- bool write{false};
- const char* filename{kDefaultBundleDataFile};
- const char* gen{kDefaultGeneratedOutputPath};
- const char* main_root_name{nullptr};
- const char* ns_name{kDefaultNamespace};
- const char* title{kDefaultTitle};
- struct {
- int c{0};
- char** v{nullptr};
- } arg;
-};
-extern Opts opts;
-
-namespace {
-namespace helper { // Part of flatbuffers API
-constexpr bool AsBinaryFile = true;
-constexpr bool AsTextFile = false;
-} // namespace helper
-
-} // namespace
-
-/**
- * Read and parse a previously generated bundle data file
- *
- **/
-int ReadBundledSchema();
-
-/**
- * Generate a bundle data file from the binary flatbuffer schema
- * files provided as input
- *
- **/
-int WriteBundledSchema();
-
-/**
- * Print tool usage options
- */
-int Usage(int argc, char** argv);
-
-/**
- * Parse tool usage options
- */
-void ParseArgs(int argc, char** argv);
diff --git a/system/gd/dumpsys/bundler/bundler_schema.fbs b/system/gd/dumpsys/bundler/bundler_schema.fbs
deleted file mode 100644
index a11fb7f150..0000000000
--- a/system/gd/dumpsys/bundler/bundler_schema.fbs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Bundled Schema
-//
-// Describes a collection of binary flatbuffer schema.
-//
-
-namespace bluetooth.dumpsys;
-
-table BundledSchemaMap {
- name:string;
- data:[ubyte];
-}
-
-table BundledSchema {
- title:string;
- root_name:string;
- map:[BundledSchemaMap];
-}
-
-root_type BundledSchema;
diff --git a/system/gd/dumpsys/bundler/extract_files_and_call.py b/system/gd/dumpsys/bundler/extract_files_and_call.py
deleted file mode 100755
index df0415f611..0000000000
--- a/system/gd/dumpsys/bundler/extract_files_and_call.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-#
-# Copyright 2021 Google, Inc.
-#
-# 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.
-""" Get contents of given files and pass as args to remaining params.
-
-Example:
- a.files = [ "foo", "bar" ]
- b.files = [ "fizz", "buzz" ]
-
- extract_files_and_call.py a.files b.files -- somebin -a --set foo -c -o
-
- will result in this call:
-
- somebin -a --set foo -c -o foo bar fizz buzz
-
-"""
-
-from __future__ import print_function
-
-import subprocess
-import sys
-
-
-def file_to_args(filename):
- """ Read file and return lines with empties removed.
- """
- with open(filename, 'r') as f:
- return [x.strip() for x in f.readlines() if x.strip()]
-
-
-def main():
- file_contents = []
- args = []
- for i in range(1, len(sys.argv) - 1):
- if sys.argv[i] == '--':
- args = sys.argv[i + 1:] + file_contents
- break
- else:
- file_contents.extend(file_to_args(sys.argv[i]))
-
- subprocess.check_call(args)
-
-
-if __name__ == "__main__":
- main()
diff --git a/system/gd/dumpsys/bundler/main.cc b/system/gd/dumpsys/bundler/main.cc
deleted file mode 100644
index e040ef2b8e..0000000000
--- a/system/gd/dumpsys/bundler/main.cc
+++ /dev/null
@@ -1,27 +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 "bundler.h"
-#include "bundler_schema_generated.h"
-
-int main(int argc, char** argv) {
- ParseArgs(argc, argv);
- if (opts.read) {
- exit(ReadBundledSchema());
- }
- if (opts.write) {
- exit(WriteBundledSchema());
- }
-}
diff --git a/system/gd/dumpsys/bundler/test.bfbs b/system/gd/dumpsys/bundler/test.bfbs
deleted file mode 100644
index 0dda6e54f8..0000000000
--- a/system/gd/dumpsys/bundler/test.bfbs
+++ /dev/null
Binary files differ
diff --git a/system/gd/dumpsys/bundler/test.cc b/system/gd/dumpsys/bundler/test.cc
deleted file mode 100644
index eebd2eacbb..0000000000
--- a/system/gd/dumpsys/bundler/test.cc
+++ /dev/null
@@ -1,89 +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 <gtest/gtest.h>
-
-#include <list>
-#include <vector>
-
-#include "bundler.h"
-#include "bundler_schema_generated.h"
-#include "flatbuffers/flatbuffers.h"
-
-// Must be run from the same directory as the test data 'test.bfbs'.
-// This is how the presubmit unit test pipeline functions.
-constexpr char kTestFilename[] = "test.bfbs";
-
-bool LoadBinarySchema(const char* filename, std::string* binary_schema);
-bool VerifyBinarySchema(const std::vector<uint8_t>& raw_schema);
-bool CreateBinarySchemaBundle(
- flatbuffers::FlatBufferBuilder* builder, const std::vector<std::string>& filenames,
- std::vector<flatbuffers::Offset<bluetooth::dumpsys::BundledSchemaMap>>* vector_map,
- std::list<std::string>* bundled_names);
-int WriteHeaderFile(FILE* fp, const uint8_t* data, size_t data_len);
-
-class BundlerTest : public ::testing::Test {
-public:
- void SetUp() override {}
-
- void TearDown() override {}
-};
-
-TEST_F(BundlerTest, LoadBinarySchema) {
- std::string string_schema;
- ASSERT_FALSE(LoadBinarySchema(nullptr, &string_schema));
- ASSERT_DEATH(LoadBinarySchema(kTestFilename, nullptr), "");
- ASSERT_TRUE(LoadBinarySchema(kTestFilename, &string_schema));
- ASSERT_FALSE(LoadBinarySchema("does_not_exist.bfbs", &string_schema));
-}
-
-TEST_F(BundlerTest, VerifyBinarySchema) {
- std::string string_schema;
- ASSERT_TRUE(LoadBinarySchema(kTestFilename, &string_schema));
- std::vector<uint8_t> raw_schema(string_schema.begin(), string_schema.end());
- ASSERT_TRUE(VerifyBinarySchema(raw_schema));
-
- std::vector<uint8_t> bogus_raw_schema(string_schema.begin() + 1, string_schema.end());
- ASSERT_FALSE(VerifyBinarySchema(bogus_raw_schema));
-}
-
-TEST_F(BundlerTest, CreateBinarySchemaBundle) {
- flatbuffers::FlatBufferBuilder builder;
- std::vector<std::string> filenames;
- std::vector<flatbuffers::Offset<bluetooth::dumpsys::BundledSchemaMap>> vector_map;
- std::list<std::string> bundled_names;
- ASSERT_TRUE(CreateBinarySchemaBundle(&builder, filenames, &vector_map, &bundled_names));
- ASSERT_EQ((unsigned int)0, vector_map.size());
-}
-
-TEST_F(BundlerTest, WriteHeaderFile) {
- std::vector<uint8_t> data;
- data.push_back(0x10);
- data.push_back(0x11);
- data.push_back(0x12);
- data.push_back(0x13);
- ASSERT_DEATH(WriteHeaderFile(nullptr, data.data(), data.size()), "");
- FILE* fp = fopen("/tmp/test.h", "w+");
- ASSERT_NE(fp, nullptr);
- WriteHeaderFile(fp, data.data(), data.size());
- fseek(fp, 0L, SEEK_SET);
- char buf[16];
- fread(buf, 1, 15, fp);
- buf[12] = '\0';
- std::string s(buf);
- ASSERT_EQ("// Generated", s);
- fclose(fp);
- unlink("/tmp/test.h");
-}
diff --git a/system/gd/dumpsys/dumpsys.h b/system/gd/dumpsys/dumpsys.h
deleted file mode 100644
index 6d2cafd465..0000000000
--- a/system/gd/dumpsys/dumpsys.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2021 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 <string>
-
-namespace bluetooth {
-namespace dumpsys {
-const std::string& GetBundledSchemaData();
-} // namespace dumpsys
-} // namespace bluetooth
diff --git a/system/gd/dumpsys/filter.cc b/system/gd/dumpsys/filter.cc
deleted file mode 100644
index 13cd2e5adf..0000000000
--- a/system/gd/dumpsys/filter.cc
+++ /dev/null
@@ -1,95 +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 "dumpsys/filter.h"
-
-#include <bluetooth/log.h>
-
-#include <memory>
-
-using namespace bluetooth;
-using namespace dumpsys;
-
-class Filter {
-public:
- Filter(const dumpsys::ReflectionSchema& reflection_schema)
- : reflection_schema_(reflection_schema) {}
-
- virtual ~Filter() = default;
-
- virtual void FilterInPlace(char* dumpsys_data) = 0;
-
- static std::unique_ptr<Filter> Factory(const dumpsys::ReflectionSchema& reflection_schema);
-
-protected:
- /**
- * Given both reflection field data and the populated flatbuffer table data, if any,
- * filter the contents of the field based upon the filtering privacy level.
- *
- * Primitives and composite strings may be successfully processed at this point.
- * Other composite types (e.g. structs or tables) must be expanded into the
- * respective grouping of subfields.
- *
- * @param field The reflection field information from the bundled schema
- * @param table The populated field data, if any
- *
- * @return true if field was filtered successfully, false otherwise.
- */
- virtual bool FilterField(const reflection::Field* /* field */, flatbuffers::Table* /* table */) {
- return false;
- }
-
- /**
- * Given both reflection object data and the populated flatbuffer table data, if any,
- * filter the object fields based upon the filtering privacy level.
- *
- * @param object The reflection object information from the bundled schema
- * @param table The populated field data, if any
- *
- */
- virtual void FilterObject(const reflection::Object* /* object */,
- flatbuffers::Table* /* table */) {}
-
- /**
- * Given both reflection field data and the populated table data, if any,
- * filter the contents of the table based upon the filtering privacy level.
- *
- * @param schema The reflection schema information from the bundled schema
- * @param table The populated field data, if any
- *
- */
- virtual void FilterTable(const reflection::Schema* /* schema */,
- flatbuffers::Table* /* table */) {}
-
- const dumpsys::ReflectionSchema& reflection_schema_;
-};
-
-class DeveloperPrivacyFilter : public Filter {
-public:
- DeveloperPrivacyFilter(const dumpsys::ReflectionSchema& reflection_schema)
- : Filter(reflection_schema) {}
- void FilterInPlace(char* /* dumpsys_data */) override { /* Nothing to do in this mode */ }
-};
-
-std::unique_ptr<Filter> Filter::Factory(const dumpsys::ReflectionSchema& reflection_schema) {
- return std::make_unique<DeveloperPrivacyFilter>(reflection_schema);
-}
-
-void bluetooth::dumpsys::FilterSchema(const ReflectionSchema& reflection_schema,
- std::string* dumpsys_data) {
- auto filter = Filter::Factory(reflection_schema);
- filter->FilterInPlace(dumpsys_data->data());
-}
diff --git a/system/gd/dumpsys/filter.h b/system/gd/dumpsys/filter.h
deleted file mode 100644
index b932b4c6bf..0000000000
--- a/system/gd/dumpsys/filter.h
+++ /dev/null
@@ -1,27 +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 <string>
-
-#include "dumpsys/reflection_schema.h"
-
-namespace bluetooth {
-namespace dumpsys {
-
-void FilterSchema(const ReflectionSchema& reflection_schema, std::string* dumpsys_data);
-
-} // namespace dumpsys
-} // namespace bluetooth
diff --git a/system/gd/dumpsys/filter_test.cc b/system/gd/dumpsys/filter_test.cc
deleted file mode 100644
index a1678ec373..0000000000
--- a/system/gd/dumpsys/filter_test.cc
+++ /dev/null
@@ -1,122 +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 "dumpsys/filter.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <list>
-#include <queue>
-
-#include "dumpsys/dumpsys_test_data.h"
-#include "test_data/bar.h"
-#include "test_data/baz.h"
-#include "test_data/foo.h"
-#include "test_data/qux.h"
-#include "test_data/root.h"
-
-using namespace bluetooth;
-
-namespace testing {
-
-class DumpsysFilterTest : public Test {
-protected:
- void SetUp() override {
- test_data_classes_.push_back(std::make_unique<BarTestDataClass>());
- test_data_classes_.push_back(std::make_unique<BazTestDataClass>());
- test_data_classes_.push_back(std::make_unique<FooTestDataClass>());
- test_data_classes_.push_back(std::make_unique<QuxTestDataClass>());
- }
-
- void TearDown() override {}
-
- std::list<std::unique_ptr<DumpsysTestDataClass>> test_data_classes_;
-
- std::string PopulateTestSchema();
-};
-
-std::string DumpsysFilterTest::PopulateTestSchema() {
- flatbuffers::FlatBufferBuilder fb_builder(1024);
-
- auto string_private = fb_builder.CreateString("String private");
- auto string_opaque = fb_builder.CreateString("String opaque");
- auto string_anonymized = fb_builder.CreateString("String anonymized");
- auto string_any = fb_builder.CreateString("String any");
-
- std::queue<TableAddFunction> queue;
- for (auto& test_data_class : test_data_classes_) {
- queue.push(test_data_class->GetTable(fb_builder));
- }
-
- testing::DumpsysTestDataRootBuilder builder(fb_builder);
-
- builder.add_string_private(string_private);
- builder.add_string_opaque(string_opaque);
- builder.add_string_anonymized(string_anonymized);
- builder.add_string_any(string_any);
-
- builder.add_int_private(123);
- builder.add_int_opaque(456);
- builder.add_int_anonymized(789);
- builder.add_int_any(0xabc);
-
- while (!queue.empty()) {
- queue.front()(&builder);
- queue.pop();
- }
- fb_builder.Finish(builder.Finish());
-
- return std::string(fb_builder.GetBufferPointer(),
- fb_builder.GetBufferPointer() + fb_builder.GetSize());
-}
-
-TEST_F(DumpsysFilterTest, filter_as_developer) {
- std::string dumpsys_data = PopulateTestSchema();
- dumpsys::ReflectionSchema reflection_schema(testing::GetBundledSchemaData());
-
- dumpsys::FilterSchema(reflection_schema, &dumpsys_data);
-
- const testing::DumpsysTestDataRoot* data_root = GetDumpsysTestDataRoot(dumpsys_data.data());
-
- ASSERT_EQ("String private", data_root->string_private()->str());
- ASSERT_EQ("String opaque", data_root->string_opaque()->str());
- ASSERT_EQ("String anonymized", data_root->string_anonymized()->str());
- ASSERT_EQ("String any", data_root->string_any()->str());
-
- ASSERT_EQ(123, data_root->int_private());
- ASSERT_EQ(456, data_root->int_opaque());
- ASSERT_EQ(789, data_root->int_anonymized());
- ASSERT_EQ(0xabc, data_root->int_any());
-
- ASSERT_EQ(nullptr, data_root->bar_module_data());
-
- const testing::FooTestSchema* foo = data_root->foo_module_data();
-
- ASSERT_EQ(123, foo->foo_int_private());
- ASSERT_EQ(123, foo->foo_int_opaque());
- ASSERT_EQ(123, foo->foo_int_anonymized());
- ASSERT_EQ(123, foo->foo_int_any());
- ASSERT_STREQ("123", foo->foo_int_string()->c_str());
-
- ASSERT_FLOAT_EQ(123.456, foo->foo_float_private());
- ASSERT_FLOAT_EQ(123.456, foo->foo_float_opaque());
- ASSERT_FLOAT_EQ(123.456, foo->foo_float_anonymized());
- ASSERT_FLOAT_EQ(123.456, foo->foo_float_any());
- ASSERT_STREQ("123.456", foo->foo_float_string()->c_str());
-}
-
-} // namespace testing
diff --git a/system/gd/dumpsys/internal/filter_internal.cc b/system/gd/dumpsys/internal/filter_internal.cc
deleted file mode 100644
index 2db2878f95..0000000000
--- a/system/gd/dumpsys/internal/filter_internal.cc
+++ /dev/null
@@ -1,289 +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 "dumpsys/internal/filter_internal.h"
-
-#include <bluetooth/log.h>
-
-#include <algorithm>
-#include <string>
-
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-
-#define DBG 0
-
-using namespace bluetooth;
-using namespace dumpsys;
-
-constexpr flatbuffers::voffset_t kErasedFromTable = 0;
-constexpr bool kFieldIsNotPopulated = true;
-constexpr bool kFieldHasBeenFiltered = true;
-constexpr bool kFieldContinueFiltering = false;
-
-void internal::ScrubFromTable(flatbuffers::Table* table, flatbuffers::voffset_t field_offset) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
- uint8_t* vtable = const_cast<uint8_t*>(table->GetVTable());
- vtable[field_offset] = kErasedFromTable;
-}
-
-void internal::ReplaceInString(flatbuffers::String* string, int c) {
- uint8_t* p = const_cast<uint8_t*>(string->Data());
- memset(p, c, string->size());
-}
-
-void internal::RandomizeInString(flatbuffers::String* string) {
- std::size_t hash = std::hash<std::string>{}(string->str());
- std::string hashed_string = std::to_string(hash);
- ReplaceInString(string, ' ');
- size_t len = std::min(static_cast<size_t>(string->size()), hashed_string.size());
- uint8_t* p = const_cast<uint8_t*>(string->Data());
- memcpy(p, hashed_string.c_str(), len);
-}
-
-const char* internal::PrivacyLevelName(PrivacyLevel privacy_level) {
- switch (privacy_level) {
- case kPrivate:
- return "Private";
- break;
- case kOpaque:
- return "Opaque";
- break;
- case kAnonymized:
- return "Anonymized";
- break;
- case kAny:
- return "Any";
- break;
- }
-}
-internal::PrivacyLevel internal::GetPrivacyLevelAttribute(const std::string& string) {
- if (string == "Any") {
- return kAny;
- } else if (string == "Anonymized") {
- return kAnonymized;
- } else if (string == "Opaque") {
- return kOpaque;
- } else if (string == "Private") {
- return kPrivate;
- }
- return kDefaultPrivacyLevel;
-}
-
-internal::PrivacyLevel internal::FindFieldPrivacyLevel(const reflection::Field& field) {
- PrivacyLevel privacy_level = kDefaultPrivacyLevel;
-
- if (field.attributes() != nullptr) {
- auto key = field.attributes()->LookupByKey(kPrivacyAttributeKeyword);
- if (key != nullptr) {
- privacy_level = internal::GetPrivacyLevelAttribute(key->value()->str());
- }
- }
- return privacy_level;
-}
-
-const reflection::Object* internal::FindReflectionObject(
- const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>* objects,
- const flatbuffers::String* name) {
- log::assert_that(objects != nullptr, "assert failed: objects != nullptr");
- log::assert_that(name != nullptr, "assert failed: name != nullptr");
- for (auto it = objects->cbegin(); it != objects->cend(); ++it) {
- if (it->name()->str() == name->str()) {
- return *it;
- }
- }
- return nullptr;
-}
-
-bool internal::FilterTypeBool(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
-
- const bool default_val = flatbuffers::GetFieldDefaultI<int8_t>(field);
- flatbuffers::voffset_t field_offset = field.offset();
-
- // boolean privacy levels are simpler.
- switch (privacy_level) {
- case kPrivate:
- case kOpaque:
- case kAnonymized:
- flatbuffers::SetField<int8_t>(table, field, default_val);
- internal::ScrubFromTable(table, field_offset);
- break;
- default:
- case kAny:
- break;
- }
- return kFieldHasBeenFiltered;
-}
-
-bool internal::FilterTypeInteger(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
- log::assert_that(flatbuffers::IsInteger(field.type()->base_type()),
- "assert failed: flatbuffers::IsInteger(field.type()->base_type())");
-
- int32_t default_val = flatbuffers::GetFieldDefaultI<int32_t>(field);
- flatbuffers::voffset_t field_offset = field.offset();
- [[maybe_unused]] int32_t val = table->GetField<int32_t>(field_offset, default_val);
-
- switch (privacy_level) {
- case kPrivate:
- flatbuffers::SetField<int32_t>(table, field, default_val);
- internal::ScrubFromTable(table, field_offset);
- break;
- case kOpaque:
- flatbuffers::SetField<int32_t>(table, field, default_val);
- break;
- case kAnonymized: {
- auto target_field = flatbuffers::GetFieldI<int32_t>(*table, field);
- int32_t new_val =
- static_cast<int32_t>(std::hash<std::string>{}(std::to_string(target_field)));
- flatbuffers::SetField<int32_t>(table, field, new_val);
- } break;
- default:
- case kAny:
- break;
- }
-
- if (DBG) {
- log::info("Integer Field_name:{} privacy_level:{} old_value:{} / 0x{:x} ==> new_value:{}",
- field.name()->c_str(), PrivacyLevelName(privacy_level), val, val,
- table->GetField<int32_t>(field_offset, default_val));
- }
- return kFieldHasBeenFiltered;
-}
-
-bool internal::FilterTypeFloat(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
- log::assert_that(flatbuffers::IsFloat(field.type()->base_type()),
- "assert failed: flatbuffers::IsFloat(field.type()->base_type())");
-
- float default_val = flatbuffers::GetFieldDefaultI<float>(field);
- flatbuffers::voffset_t field_offset = field.offset();
- [[maybe_unused]] float val = table->GetField<float>(field_offset, default_val);
- switch (privacy_level) {
- case kPrivate:
- flatbuffers::SetField<float>(table, field, default_val);
- internal::ScrubFromTable(table, field_offset);
- break;
- case kOpaque:
- flatbuffers::SetField<float>(table, field, default_val);
- break;
- case kAnonymized: {
- auto target_field = flatbuffers::GetFieldF<float>(*table, field);
- int32_t new_val = static_cast<float>(std::hash<std::string>{}(std::to_string(target_field)));
- flatbuffers::SetField<float>(table, field, new_val);
- } break;
- default:
- case kAny:
- break;
- }
- if (DBG) {
- log::info("Float Field_name:{} privacy_level:{} old_value:{:f} ==> new_value:{:f}",
- field.name()->c_str(), PrivacyLevelName(privacy_level), val,
- table->GetField<float>(field_offset, default_val));
- }
- return kFieldHasBeenFiltered;
-}
-
-bool internal::FilterTypeLong(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
-
- const int64_t default_val = flatbuffers::GetFieldDefaultI<int64_t>(field);
- flatbuffers::voffset_t field_offset = field.offset();
-
- switch (privacy_level) {
- case kPrivate:
- flatbuffers::SetField<int64_t>(table, field, default_val);
- internal::ScrubFromTable(table, field_offset);
- break;
- case kOpaque:
- flatbuffers::SetField<int64_t>(table, field, default_val);
- break;
- case kAnonymized: {
- auto target_field = flatbuffers::GetFieldI<int64_t>(*table, field);
- int64_t new_val =
- static_cast<int64_t>(std::hash<std::string>{}(std::to_string(target_field)));
- flatbuffers::SetField<int64_t>(table, field, new_val);
- } break;
- default:
- case kAny:
- break;
- }
- return kFieldHasBeenFiltered;
-}
-
-bool internal::FilterTypeString(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
- log::assert_that(field.type()->base_type() == reflection::BaseType::String,
- "assert failed: field.type()->base_type() == reflection::BaseType::String");
-
- flatbuffers::voffset_t field_offset = field.offset();
-
- const flatbuffers::String* string = flatbuffers::GetFieldS(*table, field);
- if (string == nullptr) {
- return kFieldIsNotPopulated;
- // Field is not populated
- }
- log::assert_that(string != nullptr, "assert failed: string != nullptr");
- flatbuffers::String* mutable_string = const_cast<flatbuffers::String*>(string);
-
- [[maybe_unused]] std::string old_string(string->str());
- switch (privacy_level) {
- case kPrivate:
- internal::ReplaceInString(mutable_string, '*');
- internal::ScrubFromTable(table, field_offset);
- break;
- case kOpaque:
- internal::ReplaceInString(mutable_string, '*');
- break;
- case kAnonymized:
- internal::RandomizeInString(mutable_string);
- break;
- default:
- case kAny:
- break;
- }
- if (DBG) {
- log::info("Field_name:{} size:{} privacy_level:{} old_string:{} ==> new_string:{}",
- field.name()->c_str(), string->size(), PrivacyLevelName(privacy_level), old_string,
- string->c_str());
- }
- return kFieldHasBeenFiltered;
-}
-
-bool internal::FilterTypeStruct(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level) {
- log::assert_that(table != nullptr, "assert failed: table != nullptr");
- log::assert_that(!flatbuffers::IsScalar(field.type()->base_type()),
- "assert failed: !flatbuffers::IsScalar(field.type()->base_type())");
-
- flatbuffers::voffset_t field_offset = field.offset();
-
- if (privacy_level != kAny) {
- flatbuffers::SetFieldT(table, field, nullptr);
- internal::ScrubFromTable(table, field_offset);
- if (DBG) {
- log::info("Table Removing field name:{} privacy_level:{}", field.name()->c_str(),
- PrivacyLevelName(privacy_level));
- }
- }
- return kFieldContinueFiltering;
-}
diff --git a/system/gd/dumpsys/internal/filter_internal.h b/system/gd/dumpsys/internal/filter_internal.h
deleted file mode 100644
index a18575c72f..0000000000
--- a/system/gd/dumpsys/internal/filter_internal.h
+++ /dev/null
@@ -1,157 +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.
- */
-#pragma once
-
-#include <base/strings/stringprintf.h>
-
-#include <string>
-
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-#include "macros.h"
-
-namespace bluetooth {
-namespace dumpsys {
-namespace internal {
-
-constexpr char kPrivacyAttributeKeyword[] = "privacy";
-
-enum PrivacyLevel {
- kPrivate = 0,
- kOpaque = 1,
- kAnonymized = 2,
- kAny = 4,
- kDefaultPrivacyLevel = kPrivate,
-};
-
-/**
- * Remove the field offset from flatbuffer table eliminating ability to
- * access value.
- *
- * @param table Table under consideration for field removeal
- * @param field_offset Virtual offset of field into table.
- */
-void ScrubFromTable(flatbuffers::Table* table, flatbuffers::voffset_t field_offset);
-
-/**
- * Overwrite ihe contents of flatbuffer string with the integer value proviced.
- * The entire size of the string will be set to the value provided.
- *
- * @param string Flatbuffer string under consideration for content changing.
- * @param value Value to overwrite the string contents.
- */
-void ReplaceInString(flatbuffers::String* string, int value);
-
-/**
- * Overwrite the contents of flatbuffer string with a hashed value.
- * The portion of the string greater than the hash value will be set to SPACE.
- * If the string is not large enough for the entire hash value, the hash
- * value will be truncated to the size of the string.
- *
- * @param string Flatbuffer string under consideration for content changing.
- */
-void RandomizeInString(flatbuffers::String* string);
-
-/**
- * Returns the privacy level name corresponding to the axtual numeric level.
- *
- * @param privacy_level PrivacyLevel
- *
- * @return Name of privacy level.
- */
-const char* PrivacyLevelName(PrivacyLevel privacy_level);
-
-/**
- * Returns the privacy level for the given field. If there is no explicitly
- * privacy level for this field, the default privacy level is returned.
- *
- * @param field The reflection field for the schema
- *
- * @return Privacy level enumeration value
- */
-PrivacyLevel FindFieldPrivacyLevel(const reflection::Field& field);
-
-/**
- * Returns the privacy level for given privacy level keyword name.
- * If the privacy level for this field, the default privacy level is returned.
- *
- * @param name The privacy level name.
- *
- * @return Privacy level enumeration value.
- */
-PrivacyLevel GetPrivacyLevelAttribute(const std::string& name);
-
-/**
- * Find a the reflection object that corresponds to the name provided.
- * Returns nullptr is not found.
- *
- * @param objects Vector container of flatbuffer objects
- * @param name Flatbuffer string name to search
- *
- * @return Reflection object if found, nullptr otherwise.
- */
-const reflection::Object* FindReflectionObject(
- const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>* objects,
- const flatbuffers::String* name);
-
-/**
- * Process and filter the respective data types.
- *
- * @param field The reflection field schema.
- * @param table The mutable table data corresponding to the schema.
- * @param privacy_level The privacy level in which to filter the data.
- *
- * @return true if successfully filtered, false otherwise.
- */
-bool FilterTypeBool(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level);
-bool FilterTypeFloat(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level);
-bool FilterTypeInteger(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level);
-bool FilterTypeLong(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level);
-bool FilterTypeString(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level);
-bool FilterTypeStruct(const reflection::Field& field, flatbuffers::Table* table,
- PrivacyLevel privacy_level);
-
-inline std::string FlatbufferTypeText(const flatbuffers::BaseType& type) {
- switch (type) {
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_NONE);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_BOOL);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_CHAR);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_UCHAR);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_SHORT);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_USHORT);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_INT);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_UINT);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_LONG);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_ULONG);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_FLOAT);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_DOUBLE);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_STRING);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_VECTOR);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_STRUCT);
- CASE_RETURN_TEXT(flatbuffers::BASE_TYPE_UNION);
- default:
- return base::StringPrintf("UNKNOWN[%d]", (int)type);
- }
-}
-
-} // namespace internal
-} // namespace dumpsys
-} // namespace bluetooth
diff --git a/system/gd/dumpsys/internal/filter_internal_test.cc b/system/gd/dumpsys/internal/filter_internal_test.cc
deleted file mode 100644
index 38f3481f0c..0000000000
--- a/system/gd/dumpsys/internal/filter_internal_test.cc
+++ /dev/null
@@ -1,424 +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 "dumpsys/internal/filter_internal.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "dumpsys/internal/test_data/float_bfbs.h"
-#include "dumpsys/internal/test_data/float_generated.h"
-#include "dumpsys/internal/test_data/integer_bfbs.h"
-#include "dumpsys/internal/test_data/integer_generated.h"
-#include "dumpsys/internal/test_data/string_bfbs.h"
-#include "dumpsys/internal/test_data/string_generated.h"
-#include "dumpsys/internal/test_data/struct_bfbs.h"
-#include "dumpsys/internal/test_data/struct_generated.h"
-
-namespace testing {
-
-class DumpsysFilterInternalTest : public Test {
-protected:
- void SetUp() override {}
- void TearDown() override {}
-
- flatbuffers::Table* GetMutableTable() const {
- return flatbuffers::GetMutableRoot<flatbuffers::Table>(fb_builder_.GetBufferPointer());
- }
-
- void ParseReflectionSchema(unsigned char* bfbs, unsigned int bfbs_len) {
- ASSERT_TRUE(reflection_schema_.empty());
- reflection_schema_ = std::vector<uint8_t>(bfbs, bfbs + bfbs_len);
- flatbuffers::Verifier verifier(reflection_schema_.data(), reflection_schema_.size());
- ASSERT_TRUE(reflection::VerifySchemaBuffer(verifier));
- schema_ = reflection::GetSchema(reflection_schema_.data());
- ASSERT_TRUE(schema_ != nullptr);
- }
-
- const reflection::Schema* schema_{nullptr};
- flatbuffers::FlatBufferBuilder fb_builder_ = flatbuffers::FlatBufferBuilder(1024);
-
-private:
- std::vector<uint8_t> reflection_schema_;
-};
-
-class DumpsysFilterInternalIntegerTest : public DumpsysFilterInternalTest {
-protected:
- void SetUp() override { this->ParseReflectionSchema(integer_bfbs, integer_bfbs_len); }
-
- const testing::TestTableInteger* CreateInteger(int32_t value) {
- TestTableIntegerBuilder builder(fb_builder_);
- builder.add_test_int(value);
- fb_builder_.Finish(builder.Finish());
- return GetTestTableInteger(fb_builder_.GetBufferPointer());
- }
-};
-
-class DumpsysFilterInternalFloatTest : public DumpsysFilterInternalTest {
-protected:
- void SetUp() override { this->ParseReflectionSchema(float_bfbs, float_bfbs_len); }
-
- const testing::TestTableFloat* CreateFloat(double value) {
- TestTableFloatBuilder builder(fb_builder_);
- builder.add_test_float(value);
- fb_builder_.Finish(builder.Finish());
- return GetTestTableFloat(fb_builder_.GetBufferPointer());
- }
-};
-
-class DumpsysFilterInternalStringTest : public DumpsysFilterInternalTest {
-protected:
- void SetUp() override { this->ParseReflectionSchema(string_bfbs, string_bfbs_len); }
-
- const testing::TestTableString* CreateString(std::string string) {
- auto test_string = fb_builder_.CreateString(string);
- TestTableStringBuilder builder(fb_builder_);
- builder.add_test_string(test_string);
- fb_builder_.Finish(builder.Finish());
- return GetTestTableString(fb_builder_.GetBufferPointer());
- }
-};
-
-class DumpsysFilterInternalStructTest : public DumpsysFilterInternalTest {
-protected:
- void SetUp() override { this->ParseReflectionSchema(struct_bfbs, struct_bfbs_len); }
-
- flatbuffers::Offset<TestSubTable> CreateSubTable(int val) {
- TestSubTableBuilder builder(fb_builder_);
- builder.add_placeholder(val);
- return builder.Finish();
- }
-
- const testing::TestTableStruct* CreateStruct(int val) {
- auto sub_table = CreateSubTable(val);
-
- TestTableStructBuilder builder(fb_builder_);
- builder.add_sub_table(sub_table);
- fb_builder_.Finish(builder.Finish());
- return GetTestTableStruct(fb_builder_.GetBufferPointer());
- }
-};
-
-TEST_F(DumpsysFilterInternalIntegerTest, filter_type_integer_any) {
- const testing::TestTableInteger* test_table = CreateInteger(123);
- ASSERT_EQ(123, test_table->test_int());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeInteger(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAny);
- }
- ASSERT_EQ(123, test_table->test_int());
-}
-
-TEST_F(DumpsysFilterInternalIntegerTest, filter_type_integer_anonymized) {
- const testing::TestTableInteger* test_table = CreateInteger(123);
- ASSERT_EQ(123, test_table->test_int());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeInteger(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAnonymized);
- }
- ASSERT_NE(123, test_table->test_int());
-}
-
-TEST_F(DumpsysFilterInternalIntegerTest, filter_type_integer_opaque) {
- const testing::TestTableInteger* test_table = CreateInteger(123);
- ASSERT_EQ(123, test_table->test_int());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeInteger(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kOpaque);
- }
- ASSERT_EQ(0, test_table->test_int());
-}
-
-TEST_F(DumpsysFilterInternalIntegerTest, filter_type_integer_privacy) {
- const testing::TestTableInteger* test_table = CreateInteger(123);
- ASSERT_EQ(123, test_table->test_int());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeInteger(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kPrivate);
- }
- ASSERT_EQ(0, test_table->test_int());
-}
-
-TEST_F(DumpsysFilterInternalFloatTest, filter_type_float_any) {
- const testing::TestTableFloat* test_table = CreateFloat(1.23);
- ASSERT_FLOAT_EQ(1.23, test_table->test_float());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeFloat(**it, table,
- bluetooth::dumpsys::internal::PrivacyLevel::kAny);
- }
- ASSERT_FLOAT_EQ(1.23, test_table->test_float());
-}
-
-TEST_F(DumpsysFilterInternalFloatTest, filter_type_float_anonymized) {
- const testing::TestTableFloat* test_table = CreateFloat(1.23);
- ASSERT_FLOAT_EQ(1.23, test_table->test_float());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeFloat(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAnonymized);
- }
- ASSERT_THAT(test_table->test_float(), Not(FloatEq(1.23)));
-}
-
-TEST_F(DumpsysFilterInternalFloatTest, filter_type_float_opaque) {
- const testing::TestTableFloat* test_table = CreateFloat(1.23);
- ASSERT_FLOAT_EQ(1.23, test_table->test_float());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeFloat(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kOpaque);
- }
- ASSERT_FLOAT_EQ(0.0, test_table->test_float());
-}
-
-TEST_F(DumpsysFilterInternalFloatTest, filter_type_float_private) {
- const testing::TestTableFloat* test_table = CreateFloat(1.23);
- ASSERT_FLOAT_EQ(1.23, test_table->test_float());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeFloat(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kPrivate);
- }
- ASSERT_FLOAT_EQ(0.0, test_table->test_float());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_any) {
- const testing::TestTableString* test_table = CreateString("This is a string");
- ASSERT_STREQ("This is a string", test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAny);
- }
- ASSERT_STREQ("This is a string", test_table->test_string()->c_str());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_anonymous) {
- const testing::TestTableString* test_table = CreateString("This is a string");
- ASSERT_STREQ("This is a string", test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAnonymized);
- }
- ASSERT_NE("This is a string", test_table->test_string()->c_str());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_anonymous_small) {
- const testing::TestTableString* test_table = CreateString("A");
- ASSERT_STREQ("A", test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAnonymized);
- }
- ASSERT_NE("A", test_table->test_string()->c_str());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_anonymous_large) {
- const testing::TestTableString* test_table =
- CreateString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
- ASSERT_STREQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
- test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAnonymized);
- }
- ASSERT_NE("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
- test_table->test_string()->c_str());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_opaque) {
- const testing::TestTableString* test_table = CreateString("This is a string");
- ASSERT_STREQ("This is a string", test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kOpaque);
- }
-
- std::string opaque_expected(strlen("This is a string"), '*');
- ASSERT_STREQ(opaque_expected.c_str(), test_table->test_string()->c_str());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_private) {
- const testing::TestTableString* test_table = CreateString("This is a string");
- ASSERT_STREQ("This is a string", test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kPrivate);
- }
- ASSERT_EQ(nullptr, test_table->test_string());
-}
-
-TEST_F(DumpsysFilterInternalStringTest, filter_type_string_private_small) {
- const testing::TestTableString* test_table = CreateString("A");
- ASSERT_STREQ("A", test_table->test_string()->c_str());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeString(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kPrivate);
- }
- ASSERT_EQ(nullptr, test_table->test_string());
-}
-
-TEST_F(DumpsysFilterInternalStructTest, filter_type_struct_any) {
- const testing::TestTableStruct* test_table = CreateStruct(456);
- ASSERT_EQ(456, test_table->sub_table()->placeholder());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeStruct(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAny);
- }
- ASSERT_EQ(456, test_table->sub_table()->placeholder());
-}
-
-TEST_F(DumpsysFilterInternalStructTest, filter_type_struct_anonymous) {
- const testing::TestTableStruct* test_table = CreateStruct(456);
- ASSERT_EQ(456, test_table->sub_table()->placeholder());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeStruct(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kAnonymized);
- }
- ASSERT_EQ(nullptr, test_table->sub_table());
-}
-
-TEST_F(DumpsysFilterInternalStructTest, filter_type_struct_opaque) {
- const testing::TestTableStruct* test_table = CreateStruct(456);
- ASSERT_EQ(456, test_table->sub_table()->placeholder());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeStruct(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kOpaque);
- }
- ASSERT_EQ(nullptr, test_table->sub_table());
-}
-
-TEST_F(DumpsysFilterInternalStructTest, filter_type_struct_private) {
- const testing::TestTableStruct* test_table = CreateStruct(456);
- ASSERT_EQ(456, test_table->sub_table()->placeholder());
-
- flatbuffers::Table* table = GetMutableTable();
-
- const reflection::Object* object = schema_->root_table();
- ASSERT_TRUE(object != nullptr);
-
- for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
- bluetooth::dumpsys::internal::FilterTypeStruct(
- **it, table, bluetooth::dumpsys::internal::PrivacyLevel::kPrivate);
- }
- ASSERT_EQ(nullptr, test_table->sub_table());
-}
-
-} // namespace testing
diff --git a/system/gd/dumpsys/internal/test_data/float.bfbs b/system/gd/dumpsys/internal/test_data/float.bfbs
deleted file mode 100644
index 547ecd93bf..0000000000
--- a/system/gd/dumpsys/internal/test_data/float.bfbs
+++ /dev/null
Binary files differ
diff --git a/system/gd/dumpsys/internal/test_data/float.fbs b/system/gd/dumpsys/internal/test_data/float.fbs
deleted file mode 100644
index 2f832e685c..0000000000
--- a/system/gd/dumpsys/internal/test_data/float.fbs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace testing;
-
-table TestTableFloat {
- test_float:float;
-}
-
-root_type TestTableFloat;
diff --git a/system/gd/dumpsys/internal/test_data/float_bfbs.h b/system/gd/dumpsys/internal/test_data/float_bfbs.h
deleted file mode 100644
index 06488b95a8..0000000000
--- a/system/gd/dumpsys/internal/test_data/float_bfbs.h
+++ /dev/null
@@ -1,18 +0,0 @@
-unsigned char float_bfbs[] = {
- 0x18, 0x00, 0x00, 0x00, 0x42, 0x46, 0x42, 0x53, 0x10, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x08,
- 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x04, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14,
- 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x2c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,
- 0x67, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x6c, 0x6f, 0x61,
- 0x74, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x0a,
- 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x00, 0x00};
-unsigned int float_bfbs_len = 240;
diff --git a/system/gd/dumpsys/internal/test_data/integer.bfbs b/system/gd/dumpsys/internal/test_data/integer.bfbs
deleted file mode 100644
index 110c65dbee..0000000000
--- a/system/gd/dumpsys/internal/test_data/integer.bfbs
+++ /dev/null
Binary files differ
diff --git a/system/gd/dumpsys/internal/test_data/integer.fbs b/system/gd/dumpsys/internal/test_data/integer.fbs
deleted file mode 100644
index b8a5569eb2..0000000000
--- a/system/gd/dumpsys/internal/test_data/integer.fbs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace testing;
-
-table TestTableInteger {
- test_int:int;
-}
-
-root_type TestTableInteger;
diff --git a/system/gd/dumpsys/internal/test_data/integer_bfbs.h b/system/gd/dumpsys/internal/test_data/integer_bfbs.h
deleted file mode 100644
index 7f6ba61d7e..0000000000
--- a/system/gd/dumpsys/internal/test_data/integer_bfbs.h
+++ /dev/null
@@ -1,19 +0,0 @@
-unsigned char integer_bfbs[] = {
- 0x18, 0x00, 0x00, 0x00, 0x42, 0x46, 0x42, 0x53, 0x10, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x08,
- 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x04, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14,
- 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,
- 0x67, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65,
- 0x67, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x08, 0x00, 0x0c, 0x00,
- 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00,
- 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01,
- 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x74,
- 0x00, 0x00, 0x00, 0x00};
-unsigned int integer_bfbs_len = 244;
diff --git a/system/gd/dumpsys/internal/test_data/mkfiles b/system/gd/dumpsys/internal/test_data/mkfiles
deleted file mode 100644
index 95577d05d2..0000000000
--- a/system/gd/dumpsys/internal/test_data/mkfiles
+++ /dev/null
@@ -1,9 +0,0 @@
-../../../../../out/host/linux-x86/bin/flatc -b --schema --cpp string.fbs
-xxd -i string.bfbs > string_bfbs.h
-../../../../../out/host/linux-x86/bin/flatc -b --schema --cpp integer.fbs
-xxd -i integer.bfbs > integer_bfbs.h
-../../../../../out/host/linux-x86/bin/flatc -b --schema --cpp float.fbs
-xxd -i float.bfbs > float_bfbs.h
-../../../../../out/host/linux-x86/bin/flatc -b --schema --cpp struct.fbs
-xxd -i struct.bfbs > struct_bfbs.h
-
diff --git a/system/gd/dumpsys/internal/test_data/root.h b/system/gd/dumpsys/internal/test_data/root.h
deleted file mode 100644
index 5830ee8cf0..0000000000
--- a/system/gd/dumpsys/internal/test_data/root.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-#pragma once
-
-#include "flatbuffers/flatbuffers.h"
-#include "root_generated.h"
-
-using TableAddFunction = std::function<void(testing::DumpsysTestDataRootBuilder* root_builder)>;
-
-namespace testing {
-
-struct DumpsysTestDataClass {
- virtual TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& builder) = 0;
- virtual ~DumpsysTestDataClass() = default;
-};
-
-} // namespace testing
diff --git a/system/gd/dumpsys/internal/test_data/string.bfbs b/system/gd/dumpsys/internal/test_data/string.bfbs
deleted file mode 100644
index a414802b43..0000000000
--- a/system/gd/dumpsys/internal/test_data/string.bfbs
+++ /dev/null
Binary files differ
diff --git a/system/gd/dumpsys/internal/test_data/string.fbs b/system/gd/dumpsys/internal/test_data/string.fbs
deleted file mode 100644
index ba4f2fdfc9..0000000000
--- a/system/gd/dumpsys/internal/test_data/string.fbs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace testing;
-
-table TestTableString {
- test_string:string;
-}
-
-root_type TestTableString;
diff --git a/system/gd/dumpsys/internal/test_data/string_bfbs.h b/system/gd/dumpsys/internal/test_data/string_bfbs.h
deleted file mode 100644
index 1b241352ce..0000000000
--- a/system/gd/dumpsys/internal/test_data/string_bfbs.h
+++ /dev/null
@@ -1,16 +0,0 @@
-unsigned char string_bfbs[] = {
- 0x18, 0x00, 0x00, 0x00, 0x42, 0x46, 0x42, 0x53, 0x10, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x08,
- 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x34,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x04, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
- 0x17, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x65, 0x73,
- 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x0c, 0x00,
- 0x12, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0b, 0x00, 0x00,
- 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00};
-unsigned int string_bfbs_len = 208;
diff --git a/system/gd/dumpsys/internal/test_data/struct.bfbs b/system/gd/dumpsys/internal/test_data/struct.bfbs
deleted file mode 100644
index c3ecca8841..0000000000
--- a/system/gd/dumpsys/internal/test_data/struct.bfbs
+++ /dev/null
Binary files differ
diff --git a/system/gd/dumpsys/internal/test_data/struct.fbs b/system/gd/dumpsys/internal/test_data/struct.fbs
deleted file mode 100644
index 83d4974f9b..0000000000
--- a/system/gd/dumpsys/internal/test_data/struct.fbs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace testing;
-
-table TestSubTable {
- placeholder:int;
-}
-
-table TestTableStruct{
- sub_table:TestSubTable;
-}
-
-root_type TestTableStruct;
diff --git a/system/gd/dumpsys/internal/test_data/struct_bfbs.h b/system/gd/dumpsys/internal/test_data/struct_bfbs.h
deleted file mode 100644
index 5df51a98f4..0000000000
--- a/system/gd/dumpsys/internal/test_data/struct_bfbs.h
+++ /dev/null
@@ -1,29 +0,0 @@
-unsigned char struct_bfbs[] = {
- 0x18, 0x00, 0x00, 0x00, 0x42, 0x46, 0x42, 0x53, 0x10, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x08,
- 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2c,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6c, 0xff,
- 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xac,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
- 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62,
- 0x6c, 0x65, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x08, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
- 0x28, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73,
- 0x75, 0x62, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00,
- 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74,
- 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x62, 0x54, 0x61, 0x62, 0x6c,
- 0x65, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00,
- 0x06, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14,
- 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x00, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65,
- 0x72, 0x00};
-unsigned int struct_bfbs_len = 392;
diff --git a/system/gd/dumpsys/reflection_schema.cc b/system/gd/dumpsys/reflection_schema.cc
deleted file mode 100644
index b2d79313eb..0000000000
--- a/system/gd/dumpsys/reflection_schema.cc
+++ /dev/null
@@ -1,91 +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 "dumpsys/reflection_schema.h"
-
-#include <bluetooth/log.h>
-
-#include <string>
-
-#include "bundler_schema_generated.h"
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-
-using namespace bluetooth;
-
-dumpsys::ReflectionSchema::ReflectionSchema(const std::string& pre_bundled_schema)
- : pre_bundled_schema_(pre_bundled_schema) {
- bundled_schema_ =
- flatbuffers::GetRoot<bluetooth::dumpsys::BundledSchema>(pre_bundled_schema_.data());
- log::assert_that(bundled_schema_ != nullptr, "assert failed: bundled_schema_ != nullptr");
-}
-
-int dumpsys::ReflectionSchema::GetNumberOfBundledSchemas() const {
- return bundled_schema_->map()->size();
-}
-
-std::string dumpsys::ReflectionSchema::GetTitle() const { return bundled_schema_->title()->str(); }
-
-std::string dumpsys::ReflectionSchema::GetRootName() const {
- return bundled_schema_->root_name()->str();
-}
-
-const reflection::Schema* dumpsys::ReflectionSchema::GetRootReflectionSchema() const {
- return FindInReflectionSchema(GetRootName());
-}
-
-const reflection::Schema* dumpsys::ReflectionSchema::FindInReflectionSchema(
- const std::string& name) const {
- const flatbuffers::Vector<flatbuffers::Offset<bluetooth::dumpsys::BundledSchemaMap>>* map =
- bundled_schema_->map();
-
- for (auto it = map->cbegin(); it != map->cend(); ++it) {
- if (it->name()->str() == name) {
- flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(it->data()->Data()),
- it->data()->size());
- if (!reflection::VerifySchemaBuffer(verifier)) {
- log::warn("Unable to verify schema buffer name:{}", name);
- return nullptr;
- }
- return reflection::GetSchema(it->data()->Data());
- }
- }
- return nullptr;
-}
-
-void dumpsys::ReflectionSchema::PrintReflectionSchema() const {
- const flatbuffers::Vector<flatbuffers::Offset<bluetooth::dumpsys::BundledSchemaMap>>* map =
- bundled_schema_->map();
- log::info("Bundled schema title:{} root_name:{}", bundled_schema_->title()->c_str(),
- bundled_schema_->root_name()->c_str());
- for (auto it = map->cbegin(); it != map->cend(); ++it) {
- log::info("schema:{}", it->name()->c_str());
- }
-}
-
-bool dumpsys::ReflectionSchema::VerifyReflectionSchema() const {
- const flatbuffers::Vector<flatbuffers::Offset<bluetooth::dumpsys::BundledSchemaMap>>* map =
- bundled_schema_->map();
-
- for (auto it = map->cbegin(); it != map->cend(); ++it) {
- flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(it->data()->Data()),
- it->data()->size());
- if (!reflection::VerifySchemaBuffer(verifier)) {
- return false;
- }
- }
- return true;
-}
diff --git a/system/gd/dumpsys/reflection_schema.h b/system/gd/dumpsys/reflection_schema.h
deleted file mode 100644
index 7100a6b1b6..0000000000
--- a/system/gd/dumpsys/reflection_schema.h
+++ /dev/null
@@ -1,47 +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.
- */
-
-#pragma once
-
-#include <string>
-
-#include "bundler_schema_generated.h"
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-
-namespace bluetooth {
-namespace dumpsys {
-
-class ReflectionSchema {
-public:
- ReflectionSchema(const std::string& pre_bundled_schema);
-
- std::string GetTitle() const;
- std::string GetRootName() const;
- int GetNumberOfBundledSchemas() const;
-
- bool VerifyReflectionSchema() const;
- const reflection::Schema* GetRootReflectionSchema() const;
- const reflection::Schema* FindInReflectionSchema(const std::string& name) const;
- void PrintReflectionSchema() const;
-
-private:
- const BundledSchema* bundled_schema_;
- const std::string pre_bundled_schema_;
-};
-
-} // namespace dumpsys
-} // namespace bluetooth
diff --git a/system/gd/dumpsys/reflection_schema_test.cc b/system/gd/dumpsys/reflection_schema_test.cc
deleted file mode 100644
index 83e433eddd..0000000000
--- a/system/gd/dumpsys/reflection_schema_test.cc
+++ /dev/null
@@ -1,63 +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 "dumpsys/reflection_schema.h"
-
-#include <gtest/gtest.h>
-
-#include "dumpsys/dumpsys_test_data.h"
-
-namespace bluetooth {
-namespace dumpsys {
-extern const unsigned char* data;
-extern const size_t data_size;
-const std::string& GetBundledSchemaData();
-} // namespace dumpsys
-} // namespace bluetooth
-
-namespace testing {
-
-using namespace bluetooth;
-
-class ReflectionSchemaTest : public Test {
-protected:
- void SetUp() override {}
-
- void TearDown() override {}
-};
-
-TEST_F(ReflectionSchemaTest, verify_test_content) {
- dumpsys::ReflectionSchema reflection_schema(testing::GetBundledSchemaData());
- ASSERT_EQ(5, reflection_schema.GetNumberOfBundledSchemas());
- ASSERT_TRUE(reflection_schema.FindInReflectionSchema("testing.DumpsysTestDataRoot") != nullptr);
- ASSERT_TRUE(reflection_schema.FindInReflectionSchema("testing.BarTestSchema") != nullptr);
- ASSERT_TRUE(reflection_schema.FindInReflectionSchema("testing.BazTestSchema") != nullptr);
- ASSERT_TRUE(reflection_schema.FindInReflectionSchema("testing.FooTestSchema") != nullptr);
- ASSERT_TRUE(reflection_schema.FindInReflectionSchema("testing.QuxTestSchema") != nullptr);
- ASSERT_TRUE(reflection_schema.FindInReflectionSchema("DoesNotExist") == nullptr);
-}
-
-TEST_F(ReflectionSchemaTest, verify_test_schema) {
- dumpsys::ReflectionSchema reflection_schema(testing::GetBundledSchemaData());
- ASSERT_TRUE(reflection_schema.VerifyReflectionSchema());
-}
-
-TEST_F(ReflectionSchemaTest, verify_production_schema) {
- dumpsys::ReflectionSchema reflection_schema(bluetooth::dumpsys::GetBundledSchemaData());
- ASSERT_TRUE(reflection_schema.VerifyReflectionSchema());
-}
-
-} // namespace testing
diff --git a/system/gd/dumpsys/test_data/bar.fbs b/system/gd/dumpsys/test_data/bar.fbs
deleted file mode 100644
index dc423fea9e..0000000000
--- a/system/gd/dumpsys/test_data/bar.fbs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace testing;
-
-attribute "privacy";
-
-table BarTestSchema {
- bar_x:int;
- bar_y:int;
- another_field:string (privacy:"Any");
-}
-
-root_type BarTestSchema;
-
diff --git a/system/gd/dumpsys/test_data/bar.h b/system/gd/dumpsys/test_data/bar.h
deleted file mode 100644
index 26af6c09e2..0000000000
--- a/system/gd/dumpsys/test_data/bar.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- *
- **/
-#include "bar_generated.h"
-#include "root.h"
-#include "root_generated.h"
-
-namespace testing {
-
-class BarTestDataClass : public DumpsysTestDataClass {
-public:
- TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& /* fb_builder */) override {
- return [](DumpsysTestDataRootBuilder* /* builder */) {};
- }
-};
-
-} // namespace testing
diff --git a/system/gd/dumpsys/test_data/baz.fbs b/system/gd/dumpsys/test_data/baz.fbs
deleted file mode 100644
index 38649a9c8c..0000000000
--- a/system/gd/dumpsys/test_data/baz.fbs
+++ /dev/null
@@ -1,35 +0,0 @@
-namespace testing;
-
-attribute "privacy";
-
-table BazSubTablePrivate {
- subtable_int_any:int (privacy:"Any");
- subtable_string_any:string (privacy:"Any");
-}
-
-table BazSubTableOpaque {
- subtable_int_any:int (privacy:"Any");
- subtable_string_any:string (privacy:"Any");
-}
-
-table BazSubTableAnonymized {
- subtable_int_any:int (privacy:"Any");
- subtable_string_any:string (privacy:"Any");
-}
-
-table BazSubTableAny {
- subtable_int_private:int (privacy:"Private");
- subtable_int_opaque:int (privacy:"Opaque");
- subtable_int_anonymized:int (privacy:"Anonymized");
- subtable_int_any:int (privacy:"Any");
- subtable_string_any:string (privacy:"Any");
-}
-
-table BazTestSchema {
- sub_table_private:BazSubTablePrivate; // private by default
- sub_table_opaque:BazSubTableOpaque (privacy:"Opaque");
- sub_table_anonymized:BazSubTableAnonymized (privacy:"Anonymized");
- sub_table_any:BazSubTableAny (privacy:"Any");
-}
-
-root_type BazTestSchema;
diff --git a/system/gd/dumpsys/test_data/baz.h b/system/gd/dumpsys/test_data/baz.h
deleted file mode 100644
index 326f025bb9..0000000000
--- a/system/gd/dumpsys/test_data/baz.h
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#include "baz_generated.h"
-#include "root.h"
-#include "root_generated.h"
-
-namespace testing {
-
-class BazTestDataClass : public DumpsysTestDataClass {
-public:
- TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& fb_builder) override {
- auto sub_name_private = fb_builder.CreateString("Baz Subtable Private");
- auto sub_name_opaque = fb_builder.CreateString("Baz Subtable Opaque");
- auto sub_name_anonymized = fb_builder.CreateString("Baz Subtable Anonymized");
- auto sub_name_any = fb_builder.CreateString("Baz Subtable Any");
-
- auto private_subtable = CreateBazSubTablePrivate(fb_builder, 1, sub_name_private);
- auto opaque_subtable = CreateBazSubTableOpaque(fb_builder, 1, sub_name_opaque);
- auto anonymized_subtable = CreateBazSubTableAnonymized(fb_builder, 1, sub_name_anonymized);
- auto any_subtable = CreateBazSubTableAny(fb_builder, 1, 2, 3, 4, sub_name_any);
-
- BazTestSchemaBuilder builder(fb_builder);
- builder.add_sub_table_private(private_subtable);
- builder.add_sub_table_opaque(opaque_subtable);
- builder.add_sub_table_anonymized(anonymized_subtable);
- builder.add_sub_table_any(any_subtable);
- auto baz_table = builder.Finish();
-
- return [baz_table](DumpsysTestDataRootBuilder* builder) {
- builder->add_baz_module_data(baz_table);
- };
- }
-};
-
-} // namespace testing
diff --git a/system/gd/dumpsys/test_data/foo.fbs b/system/gd/dumpsys/test_data/foo.fbs
deleted file mode 100644
index b7482c326f..0000000000
--- a/system/gd/dumpsys/test_data/foo.fbs
+++ /dev/null
@@ -1,25 +0,0 @@
-namespace testing;
-
-attribute "privacy";
-
-table FooTestSchema {
- foo_int_private:int;
- foo_int_opaque:int (privacy:"Opaque");
- foo_int_anonymized:int (privacy:"Anonymized");
- foo_int_any:int (privacy:"Any");
- foo_int_string:string (privacy:"Any");
-
- foo_float_private:float;
- foo_float_opaque:float (privacy:"Opaque");
- foo_float_anonymized:float (privacy:"Anonymized");
- foo_float_any:float (privacy:"Any");
- foo_float_string:string (privacy:"Any");
-
- foo_bool_private:bool (privacy:"Private");
- foo_bool_opaque:bool (privacy:"Opaque");
- foo_bool_anonymized:bool (privacy:"Anonymized");
- foo_bool_any:bool (privacy:"Any");
- foo_bool_string:string (privacy:"Any");
-}
-
-root_type FooTestSchema;
diff --git a/system/gd/dumpsys/test_data/foo.h b/system/gd/dumpsys/test_data/foo.h
deleted file mode 100644
index 7d346657d4..0000000000
--- a/system/gd/dumpsys/test_data/foo.h
+++ /dev/null
@@ -1,42 +0,0 @@
-
-#include "foo_generated.h"
-#include "root.h"
-#include "root_generated.h"
-
-namespace testing {
-
-class FooTestDataClass : public DumpsysTestDataClass {
-public:
- TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& fb_builder) override {
- auto int_string = fb_builder.CreateString("123");
- auto float_string = fb_builder.CreateString("123.456");
- auto bool_string = fb_builder.CreateString("true");
-
- FooTestSchemaBuilder builder(fb_builder);
- builder.add_foo_int_private(123);
- builder.add_foo_int_opaque(123);
- builder.add_foo_int_anonymized(123);
- builder.add_foo_int_any(123);
- builder.add_foo_int_string(int_string);
-
- builder.add_foo_float_private(123.456);
- builder.add_foo_float_opaque(123.456);
- builder.add_foo_float_anonymized(123.456);
- builder.add_foo_float_any(123.456);
- builder.add_foo_float_string(float_string);
-
- builder.add_foo_bool_private(true);
- builder.add_foo_bool_opaque(true);
- builder.add_foo_bool_anonymized(true);
- builder.add_foo_bool_any(true);
- builder.add_foo_bool_string(bool_string);
-
- auto foo_table = builder.Finish();
-
- return [foo_table](DumpsysTestDataRootBuilder* builder) {
- builder->add_foo_module_data(foo_table);
- };
- }
-};
-
-} // namespace testing
diff --git a/system/gd/dumpsys/test_data/qux.fbs b/system/gd/dumpsys/test_data/qux.fbs
deleted file mode 100644
index 15e17dab7d..0000000000
--- a/system/gd/dumpsys/test_data/qux.fbs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace testing;
-
-attribute "privacy";
-
-table QuxTestSchema {
- qux_int_private:int;
- qux_int_opaque:int (privacy:"Opaque");
- qux_int_anonymized:int (privacy:"Anonymized");
- qux_int_any:int (privacy:"Any");
- qux_string_name:string (privacy:"Any");
-}
-
-root_type QuxTestSchema;
diff --git a/system/gd/dumpsys/test_data/qux.h b/system/gd/dumpsys/test_data/qux.h
deleted file mode 100644
index 1e70de3879..0000000000
--- a/system/gd/dumpsys/test_data/qux.h
+++ /dev/null
@@ -1,28 +0,0 @@
-
-#include "qux_generated.h"
-#include "root.h"
-#include "root_generated.h"
-
-namespace testing {
-
-class QuxTestDataClass : public DumpsysTestDataClass {
-public:
- TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& fb_builder) override {
- auto name = fb_builder.CreateString("Qux Module String");
-
- QuxTestSchemaBuilder builder(fb_builder);
- builder.add_qux_int_private(123);
- builder.add_qux_int_opaque(456);
- builder.add_qux_int_anonymized(789);
- builder.add_qux_int_any(0xabc);
- builder.add_qux_string_name(name);
-
- auto qux_table = builder.Finish();
-
- return [qux_table](DumpsysTestDataRootBuilder* builder) {
- builder->add_qux_module_data(qux_table);
- };
- }
-};
-
-} // namespace testing
diff --git a/system/gd/dumpsys/test_data/root.fbs b/system/gd/dumpsys/test_data/root.fbs
deleted file mode 100644
index cedd310d11..0000000000
--- a/system/gd/dumpsys/test_data/root.fbs
+++ /dev/null
@@ -1,27 +0,0 @@
-include "foo.fbs";
-include "bar.fbs";
-include "baz.fbs";
-include "qux.fbs";
-
-namespace testing;
-
-attribute "privacy";
-
-table DumpsysTestDataRoot {
- string_private:string;
- string_opaque:string (privacy:"Opaque");
- string_anonymized:string (privacy:"Anonymized");
- string_any:string (privacy:"Any");
-
- int_private:int32 (privacy:"Private");
- int_opaque:int32 (privacy:"Opaque");
- int_anonymized:int32 (privacy:"Anonymized");
- int_any:int32 (privacy:"Any");
-
- foo_module_data:FooTestSchema (privacy:"Any");
- bar_module_data:BarTestSchema (privacy:"Any");
- baz_module_data:BazTestSchema (privacy:"Any");
- qux_module_data:QuxTestSchema (privacy:"Any");
-}
-
-root_type DumpsysTestDataRoot;
diff --git a/system/gd/dumpsys/test_data/root.h b/system/gd/dumpsys/test_data/root.h
deleted file mode 100644
index 9f58c8ebed..0000000000
--- a/system/gd/dumpsys/test_data/root.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-#pragma once
-
-#include "flatbuffers/flatbuffers.h"
-#include "root_generated.h"
-
-using TableAddFunction = std::function<void(testing::DumpsysTestDataRootBuilder* root_builder)>;
-
-namespace testing {
-
-struct DumpsysTestDataClass {
- virtual TableAddFunction GetTable(flatbuffers::FlatBufferBuilder& fb_builder) = 0;
- virtual ~DumpsysTestDataClass() = default;
-};
-
-} // namespace testing
diff --git a/system/gd/dumpsys_data.fbs b/system/gd/dumpsys_data.fbs
deleted file mode 100644
index 2556a4da4f..0000000000
--- a/system/gd/dumpsys_data.fbs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Top level module dumpsys data schema
-//
-// Possible field privacy levels from strongest to weakest.
-// When unspecified defaults to the strongest privacy level.
-//
-// privacy:"Private"
-// privacy:"Opaque"
-// privacy:"Anonymized"
-// privacy:"Any"
-
-
-include "module_unittest.fbs";
-include "os/wakelock_manager.fbs";
-
-namespace bluetooth;
-
-attribute "privacy";
-
-table DumpsysData {
- title:string (privacy:"Any");
- wakelock_manager_data:bluetooth.os.WakelockManagerData (privacy:"Any");
- module_unittest_data:bluetooth.ModuleUnitTestData; // private
-}
-
-root_type DumpsysData;
diff --git a/system/gd/facade/facade_main.cc b/system/gd/facade/facade_main.cc
deleted file mode 100644
index 4745ce2c06..0000000000
--- a/system/gd/facade/facade_main.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2019 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 <bluetooth/log.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <csignal>
-#include <cstring>
-#include <optional>
-#include <string>
-#include <thread>
-
-#include "stack_manager.h"
-
-// clang-format off
-#include <client/linux/handler/exception_handler.h>
-#include <unwindstack/AndroidUnwinder.h>
-// clang-format on
-
-#include "facade/grpc_root_server.h"
-#include "hal/hci_hal_host.h"
-#include "hal/snoop_logger.h"
-#include "os/parameter_provider.h"
-#include "os/system_properties.h"
-
-using ::bluetooth::ModuleList;
-using ::bluetooth::StackManager;
-using ::bluetooth::hal::HciHalHostRootcanalConfig;
-using ::bluetooth::os::Thread;
-using namespace bluetooth;
-
-extern "C" const char* __asan_default_options() { return "detect_container_overflow=0"; }
-
-namespace {
-::bluetooth::facade::GrpcRootServer grpc_root_server;
-
-std::promise<void> interrupt_promise;
-std::future<void> interrupt_future;
-bool interrupted = false;
-struct sigaction old_act = {};
-void interrupt_handler(int signal_number) {
- if (!interrupted) {
- interrupted = true;
- log::info("Stopping gRPC root server due to signal: {}[{}]", strsignal(signal_number),
- signal_number);
- interrupt_promise.set_value();
- } else {
- log::warn("Already interrupted by signal: {}[{}]", strsignal(signal_number), signal_number);
- }
- if (old_act.sa_handler != nullptr && old_act.sa_handler != SIG_IGN &&
- old_act.sa_handler != SIG_DFL) {
- log::info("Calling saved signal handler");
- old_act.sa_handler(signal_number);
- }
-}
-struct sigaction new_act = {.sa_handler = interrupt_handler};
-
-bool crash_callback(const void* crash_context, size_t crash_context_size, void* /* context */) {
- std::optional<pid_t> tid;
- if (crash_context_size >= sizeof(google_breakpad::ExceptionHandler::CrashContext)) {
- auto* ctx = static_cast<const google_breakpad::ExceptionHandler::CrashContext*>(crash_context);
- tid = ctx->tid;
- int signal_number = ctx->siginfo.si_signo;
- log::error("Process crashed, signal: {}[{}], tid: {}", strsignal(signal_number), signal_number,
- ctx->tid);
- } else {
- log::error("Process crashed, signal: unknown, tid: unknown");
- }
- unwindstack::AndroidLocalUnwinder unwinder;
- unwindstack::AndroidUnwinderData data;
- if (!unwinder.Unwind(tid, data)) {
- log::error("Unwind failed");
- return false;
- }
- log::error("Backtrace:");
- for (const auto& frame : data.frames) {
- log::error("{}", unwinder.FormatFrame(frame));
- }
- return true;
-}
-
-// Need to stop server on a thread that is not part of a signal handler due to an issue with gRPC
-// See: https://github.com/grpc/grpc/issues/24884
-void thread_check_shutdown() {
- log::info("shutdown thread waiting for interruption");
- interrupt_future.wait();
- log::info("interrupted, stopping server");
- grpc_root_server.StopServer();
-}
-
-} // namespace
-
-// The entry point for the binary with libbluetooth + facades
-int main(int argc, const char** argv) {
- google_breakpad::MinidumpDescriptor descriptor(
- google_breakpad::MinidumpDescriptor::kMicrodumpOnConsole);
- google_breakpad::ExceptionHandler eh(descriptor, nullptr, nullptr, nullptr, true, -1);
- eh.set_crash_handler(crash_callback);
-
- int root_server_port = 8897;
- int grpc_port = 8899;
-
- const std::string arg_grpc_root_server_port = "--root-server-port=";
- const std::string arg_grpc_server_port = "--grpc-port=";
- const std::string arg_rootcanal_port = "--rootcanal-port=";
- const std::string arg_btsnoop_path = "--btsnoop=";
- const std::string arg_btsnooz_path = "--btsnooz=";
- const std::string arg_btconfig_path = "--btconfig=";
- for (int i = 1; i < argc; i++) {
- std::string arg = argv[i];
- if (arg.find(arg_grpc_root_server_port) == 0) {
- auto port_number = arg.substr(arg_grpc_root_server_port.size());
- root_server_port = std::stoi(port_number);
- }
- if (arg.find(arg_grpc_server_port) == 0) {
- auto port_number = arg.substr(arg_grpc_server_port.size());
- grpc_port = std::stoi(port_number);
- }
- if (arg.find(arg_rootcanal_port) == 0) {
- auto port_number = arg.substr(arg_rootcanal_port.size());
- HciHalHostRootcanalConfig::Get()->SetPort(std::stoi(port_number));
- }
- if (arg.find(arg_btsnoop_path) == 0) {
- auto btsnoop_path = arg.substr(arg_btsnoop_path.size());
- ::bluetooth::os::ParameterProvider::OverrideSnoopLogFilePath(btsnoop_path);
- log::assert_that(::bluetooth::os::SetSystemProperty(
- ::bluetooth::hal::SnoopLogger::kBtSnoopLogModeProperty,
- ::bluetooth::hal::SnoopLogger::kBtSnoopLogModeFull),
- "assert failed: ::bluetooth::os::SetSystemProperty( "
- "::bluetooth::hal::SnoopLogger::kBtSnoopLogModeProperty, "
- "::bluetooth::hal::SnoopLogger::kBtSnoopLogModeFull)");
- }
- if (arg.find(arg_btsnooz_path) == 0) {
- auto btsnooz_path = arg.substr(arg_btsnooz_path.size());
- ::bluetooth::os::ParameterProvider::OverrideSnoozLogFilePath(btsnooz_path);
- }
- if (arg.find(arg_btconfig_path) == 0) {
- auto btconfig_path = arg.substr(arg_btconfig_path.size());
- ::bluetooth::os::ParameterProvider::OverrideConfigFilePath(btconfig_path);
- }
- }
-
- int ret = sigaction(SIGINT, &new_act, &old_act);
- if (ret < 0) {
- log::error("sigaction error: {}", strerror(errno));
- }
-
- log::info("Starting Server");
- grpc_root_server.StartServer("0.0.0.0", root_server_port, grpc_port);
- log::info("Server started");
- auto wait_thread = std::thread([] { grpc_root_server.RunGrpcLoop(); });
- interrupt_future = interrupt_promise.get_future();
- auto shutdown_thread = std::thread{thread_check_shutdown};
- wait_thread.join();
- log::info("Server terminated");
- shutdown_thread.join();
- log::info("Shutdown thread terminated");
-
- return 0;
-}
diff --git a/system/gd/facade/grpc_root_server.cc b/system/gd/facade/grpc_root_server.cc
deleted file mode 100644
index 8e3bfb3f3f..0000000000
--- a/system/gd/facade/grpc_root_server.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2019 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 "facade/grpc_root_server.h"
-
-#include <string>
-
-#include "blueberry/facade/rootservice.grpc.pb.h"
-#include "facade/read_only_property_server.h"
-#include "grpc/grpc_module.h"
-#include "hal/facade.h"
-#include "hci/facade/acl_manager_facade.h"
-#include "hci/facade/controller_facade.h"
-#include "hci/facade/facade.h"
-#include "hci/facade/le_acl_manager_facade.h"
-#include "hci/facade/le_advertising_manager_facade.h"
-#include "hci/facade/le_initiator_address_facade.h"
-#include "hci/facade/le_scanning_manager_facade.h"
-#include "neighbor/facade/facade.h"
-#include "os/thread.h"
-#include "stack_manager.h"
-
-namespace bluetooth {
-namespace facade {
-
-using ::blueberry::facade::BluetoothModule;
-using ::bluetooth::grpc::GrpcModule;
-using ::bluetooth::os::Thread;
-
-class RootFacadeService : public ::blueberry::facade::RootFacade::Service {
-public:
- explicit RootFacadeService(int grpc_port) : grpc_port_(grpc_port) {}
-
- ::grpc::Status StartStack(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::StartStackRequest* request,
- ::blueberry::facade::StartStackResponse* /* response */) override {
- if (is_running_) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is running");
- }
-
- ModuleList modules;
- modules.add<::bluetooth::grpc::GrpcModule>();
-
- BluetoothModule module_under_test = request->module_under_test();
- switch (module_under_test) {
- case BluetoothModule::HAL:
- modules.add<::bluetooth::hal::HciHalFacadeModule>();
- break;
- case BluetoothModule::HCI:
- modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
- modules.add<::bluetooth::hci::facade::HciFacadeModule>();
- break;
- case BluetoothModule::HCI_INTERFACES:
- modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
- modules.add<::bluetooth::hci::facade::HciFacadeModule>();
- modules.add<::bluetooth::hci::facade::AclManagerFacadeModule>();
- modules.add<::bluetooth::hci::facade::ControllerFacadeModule>();
- modules.add<::bluetooth::hci::facade::LeAclManagerFacadeModule>();
- modules.add<::bluetooth::hci::facade::LeAdvertisingManagerFacadeModule>();
- modules.add<::bluetooth::hci::facade::LeInitiatorAddressFacadeModule>();
- modules.add<::bluetooth::hci::facade::LeScanningManagerFacadeModule>();
- modules.add<::bluetooth::neighbor::facade::NeighborFacadeModule>();
- break;
- default:
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
- }
-
- stack_thread_ = std::make_unique<Thread>("stack_thread", Thread::Priority::NORMAL);
- stack_manager_.StartUp(&modules, stack_thread_.get());
-
- GrpcModule* grpc_module = stack_manager_.GetInstance<GrpcModule>();
- grpc_module->StartServer("0.0.0.0", grpc_port_);
-
- grpc_loop_thread_ =
- std::make_unique<std::thread>([grpc_module] { grpc_module->RunGrpcLoop(); });
- is_running_ = true;
-
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status StopStack(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::StopStackRequest* /* request */,
- ::blueberry::facade::StopStackResponse* /* response */) override {
- if (!is_running_) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is not running");
- }
-
- stack_manager_.GetInstance<GrpcModule>()->StopServer();
- grpc_loop_thread_->join();
- grpc_loop_thread_.reset();
-
- stack_manager_.ShutDown();
- stack_thread_.reset();
- is_running_ = false;
- return ::grpc::Status::OK;
- }
-
-private:
- std::unique_ptr<Thread> stack_thread_ = nullptr;
- bool is_running_ = false;
- std::unique_ptr<std::thread> grpc_loop_thread_ = nullptr;
- StackManager stack_manager_;
- int grpc_port_ = 8898;
-};
-
-struct GrpcRootServer::impl {
- bool started_ = false;
- std::unique_ptr<RootFacadeService> root_facade_service_ = nullptr;
- std::unique_ptr<::grpc::Server> server_ = nullptr;
-};
-
-GrpcRootServer::GrpcRootServer() : pimpl_(new impl()) {}
-
-GrpcRootServer::~GrpcRootServer() = default;
-
-void GrpcRootServer::StartServer(const std::string& address, int grpc_root_server_port,
- int grpc_port) {
- log::assert_that(!pimpl_->started_, "assert failed: !pimpl_->started_");
- pimpl_->started_ = true;
-
- std::string listening_port = address + ":" + std::to_string(grpc_root_server_port);
- ::grpc::ServerBuilder builder;
-
- pimpl_->root_facade_service_ = std::make_unique<RootFacadeService>(grpc_port);
- builder.RegisterService(pimpl_->root_facade_service_.get());
- builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
- pimpl_->server_ = builder.BuildAndStart();
-
- log::assert_that(pimpl_->server_ != nullptr, "assert failed: pimpl_->server_ != nullptr");
-}
-
-void GrpcRootServer::StopServer() {
- log::assert_that(pimpl_->started_, "assert failed: pimpl_->started_");
- pimpl_->server_->Shutdown();
- pimpl_->started_ = false;
-}
-
-void GrpcRootServer::RunGrpcLoop() {
- log::assert_that(pimpl_->started_, "assert failed: pimpl_->started_");
- pimpl_->server_->Wait();
-}
-
-} // namespace facade
-} // namespace bluetooth
diff --git a/system/gd/facade/read_only_property_server.cc b/system/gd/facade/read_only_property_server.cc
deleted file mode 100644
index d8a646d774..0000000000
--- a/system/gd/facade/read_only_property_server.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2019 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 "facade/read_only_property_server.h"
-
-#include "hci/controller.h"
-
-namespace bluetooth {
-namespace facade {
-
-class ReadOnlyPropertyService : public blueberry::facade::ReadOnlyProperty::Service {
-public:
- ReadOnlyPropertyService(hci::Controller* controller) : controller_(controller) {}
- ::grpc::Status ReadLocalAddress(::grpc::ServerContext* /* context */,
- const ::google::protobuf::Empty* /* request */,
- ::blueberry::facade::BluetoothAddress* response) override {
- auto address = controller_->GetMacAddress().ToString();
- response->set_address(address);
- return ::grpc::Status::OK;
- }
-
-private:
- hci::Controller* controller_;
-};
-
-void ReadOnlyPropertyServerModule::ListDependencies(ModuleList* list) const {
- GrpcFacadeModule::ListDependencies(list);
- list->add<hci::Controller>();
-}
-void ReadOnlyPropertyServerModule::Start() {
- GrpcFacadeModule::Start();
- service_ = std::make_unique<ReadOnlyPropertyService>(GetDependency<hci::Controller>());
-}
-void ReadOnlyPropertyServerModule::Stop() {
- service_.reset();
- GrpcFacadeModule::Stop();
-}
-::grpc::Service* ReadOnlyPropertyServerModule::GetService() const { return service_.get(); }
-
-const ModuleFactory ReadOnlyPropertyServerModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new ReadOnlyPropertyServerModule(); });
-
-} // namespace facade
-} // namespace bluetooth
diff --git a/system/gd/facade/read_only_property_server.h b/system/gd/facade/read_only_property_server.h
deleted file mode 100644
index a71d5fbd93..0000000000
--- a/system/gd/facade/read_only_property_server.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include <memory>
-
-#include "blueberry/facade/rootservice.grpc.pb.h"
-#include "grpc/grpc_module.h"
-
-namespace bluetooth {
-namespace facade {
-
-class ReadOnlyPropertyService;
-
-class ReadOnlyPropertyServerModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- std::unique_ptr<ReadOnlyPropertyService> service_;
-};
-
-} // namespace facade
-} // namespace bluetooth
diff --git a/system/gd/grpc/grpc_event_queue.h b/system/gd/grpc/grpc_event_queue.h
deleted file mode 100644
index c7f8c87314..0000000000
--- a/system/gd/grpc/grpc_event_queue.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2019 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 <bluetooth/log.h>
-#include <grpc++/grpc++.h>
-
-#include <atomic>
-#include <chrono>
-#include <utility>
-
-#include "blueberry/facade/common.pb.h"
-#include "common/blocking_queue.h"
-
-namespace bluetooth {
-namespace grpc {
-
-template <typename T>
-class GrpcEventQueue {
-public:
- /**
- * Create a GrpcEventQueue that can be used to shuffle event from one thread to another
- * @param log_name
- */
- explicit GrpcEventQueue(std::string log_name) : log_name_(std::move(log_name)) {}
-
- /**
- * Run the event loop and blocks until client cancels the stream request
- * Event queue will be cleared before entering the loop. Hence, only events occurred after gRPC
- * request will be delivered to the user. Hence user is advised to run the loop before generating
- * pending events.
- *
- * @param context client context
- * @param writer output writer
- * @return gRPC status
- */
- ::grpc::Status RunLoop(::grpc::ServerContext* context, ::grpc::ServerWriter<T>* writer) {
- using namespace std::chrono_literals;
- log::info("{}: Entering Loop", log_name_);
- while (!context->IsCancelled()) {
- // Wait for 100 ms so that cancellation can be caught in amortized 50 ms latency
- if (pending_events_.wait_to_take(100ms)) {
- log::info("{}: Got event from queue", log_name_);
- writer->Write(pending_events_.take());
- }
- }
- running_ = false;
- log::info("{}: Exited Loop", log_name_);
- return ::grpc::Status::OK;
- }
-
- /**
- * Called when there is an incoming event
- * @param event incoming event
- */
- void OnIncomingEvent(T event) {
- if (!running_) {
- log::info("{}: Discarding an event while not running the loop", log_name_);
- return;
- }
- log::info("{}: Got event, enqueuing", log_name_);
- pending_events_.push(std::move(event));
- }
-
-private:
- std::string log_name_;
- std::atomic<bool> running_{true};
- common::BlockingQueue<T> pending_events_;
-};
-
-} // namespace grpc
-} // namespace bluetooth
diff --git a/system/gd/grpc/grpc_module.cc b/system/gd/grpc/grpc_module.cc
deleted file mode 100644
index 53b40f8035..0000000000
--- a/system/gd/grpc/grpc_module.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2019 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 "grpc/grpc_module.h"
-
-#include <bluetooth/log.h>
-
-using ::grpc::Server;
-using ::grpc::ServerBuilder;
-
-namespace bluetooth {
-namespace grpc {
-
-void GrpcModule::ListDependencies(ModuleList* /* list */) const {}
-
-void GrpcModule::Start() { log::assert_that(!started_, "assert failed: !started_"); }
-
-void GrpcModule::Stop() { log::assert_that(!started_, "assert failed: !started_"); }
-
-void GrpcModule::StartServer(const std::string& address, int port) {
- log::assert_that(!started_, "assert failed: !started_");
- started_ = true;
-
- std::string listening_port = address + ":" + std::to_string(port);
- ServerBuilder builder;
-
- for (const auto& facade : facades_) {
- builder.RegisterService(facade->GetService());
- }
-
- builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
- completion_queue_ = builder.AddCompletionQueue();
- server_ = builder.BuildAndStart();
- log::assert_that(server_ != nullptr, "assert failed: server_ != nullptr");
- log::info("gRPC server started on {}", listening_port);
-
- for (const auto& facade : facades_) {
- facade->OnServerStarted();
- }
-}
-
-void GrpcModule::StopServer() {
- log::assert_that(started_, "assert failed: started_");
-
- server_->Shutdown();
- completion_queue_->Shutdown();
-
- for (const auto& facade : facades_) {
- facade->OnServerStopped();
- }
-
- started_ = false;
-}
-
-void GrpcModule::Register(GrpcFacadeModule* facade) {
- log::assert_that(!started_, "assert failed: !started_");
-
- facades_.push_back(facade);
-}
-
-void GrpcModule::Unregister(GrpcFacadeModule* facade) {
- log::assert_that(!started_, "assert failed: !started_");
-
- for (auto it = facades_.begin(); it != facades_.end(); it++) {
- if (*it == facade) {
- facades_.erase(it);
- return;
- }
- }
-
- log::fatal("module not found");
-}
-
-void GrpcModule::RunGrpcLoop() {
- void* tag;
- bool ok;
- while (true) {
- if (!completion_queue_->Next(&tag, &ok)) {
- log::info("gRPC is shutdown");
- break;
- }
- }
-}
-
-std::string GrpcModule::ToString() const { return "Grpc Module"; }
-
-const ::bluetooth::ModuleFactory GrpcModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new GrpcModule(); });
-
-void GrpcFacadeModule::ListDependencies(ModuleList* list) const { list->add<GrpcModule>(); }
-
-void GrpcFacadeModule::Start() { GetDependency<GrpcModule>()->Register(this); }
-
-void GrpcFacadeModule::Stop() { GetDependency<GrpcModule>()->Unregister(this); }
-
-std::string GrpcFacadeModule::ToString() const { return "Grpc Facade Module"; }
-
-} // namespace grpc
-} // namespace bluetooth
diff --git a/system/gd/grpc/grpc_module.h b/system/gd/grpc/grpc_module.h
deleted file mode 100644
index e1b8158b82..0000000000
--- a/system/gd/grpc/grpc_module.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-#include <module.h>
-
-#include <functional>
-#include <vector>
-
-namespace bluetooth {
-namespace grpc {
-
-class GrpcFacadeModule;
-
-class GrpcModule : public ::bluetooth::Module {
-public:
- static const ModuleFactory Factory;
-
- void StartServer(const std::string& address, int port);
-
- void StopServer();
-
- void Register(GrpcFacadeModule* facade);
-
- void Unregister(GrpcFacadeModule* facade);
-
- // Blocks for incoming gRPC requests
- void RunGrpcLoop();
-
-protected:
- void ListDependencies(ModuleList* list) const override;
-
- void Start() override;
-
- void Stop() override;
-
- std::string ToString() const override;
-
-private:
- bool started_;
- std::unique_ptr<::grpc::Server> server_ = nullptr;
- std::unique_ptr<::grpc::ServerCompletionQueue> completion_queue_ = nullptr;
- std::vector<GrpcFacadeModule*> facades_;
-};
-
-class GrpcFacadeModule : public ::bluetooth::Module {
- friend GrpcModule;
-
-protected:
- void ListDependencies(ModuleList* list) const override;
-
- void Start() override;
-
- void Stop() override;
-
- virtual ::grpc::Service* GetService() const = 0;
-
- virtual void OnServerStarted() {}
-
- virtual void OnServerStopped() {}
-
- std::string ToString() const override;
-};
-
-} // namespace grpc
-} // namespace bluetooth
diff --git a/system/gd/hal/Android.bp b/system/gd/hal/Android.bp
index 91e1573c0e..28c286ebba 100644
--- a/system/gd/hal/Android.bp
+++ b/system/gd/hal/Android.bp
@@ -43,6 +43,20 @@ filegroup {
}
filegroup {
+ name: "BluetoothHalSources_socket_android",
+ srcs: [
+ "socket_hal_android.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalSources_socket_host",
+ srcs: [
+ "socket_hal_host.cc",
+ ],
+}
+
+filegroup {
name: "BluetoothHalSources_hci_android_hidl",
srcs: [
"hci_backend_aidl.cc",
@@ -73,13 +87,6 @@ filegroup {
}
filegroup {
- name: "BluetoothFacade_hci_hal",
- srcs: [
- "facade.cc",
- ],
-}
-
-filegroup {
name: "BluetoothHalFuzzSources",
srcs: [
"fuzz/fuzz_hci_hal.cc",
diff --git a/system/gd/hal/BUILD.gn b/system/gd/hal/BUILD.gn
index 46be6e9d8a..ebf15255af 100644
--- a/system/gd/hal/BUILD.gn
+++ b/system/gd/hal/BUILD.gn
@@ -53,3 +53,12 @@ source_set("BluetoothHalSources_ranging_host") {
configs += [ "//bt/system/gd:gd_defaults" ]
deps = [ "//bt/system/gd:gd_default_deps" ]
}
+
+source_set("BluetoothHalSources_socket_host") {
+ sources = [
+ "socket_hal_host.cc",
+ ]
+
+ configs += [ "//bt/system/gd:gd_defaults" ]
+ deps = [ "//bt/system/gd:gd_default_deps" ]
+}
diff --git a/system/gd/hal/facade.cc b/system/gd/hal/facade.cc
deleted file mode 100644
index 9cfefd7a77..0000000000
--- a/system/gd/hal/facade.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2019 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 "hal/facade.h"
-
-#include <memory>
-#include <mutex>
-
-#include "blueberry/facade/hal/hal_facade.grpc.pb.h"
-#include "grpc/grpc_event_queue.h"
-#include "hal/hci_hal.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-namespace bluetooth {
-namespace hal {
-
-class HciHalFacadeService : public blueberry::facade::hal::HciHalFacade::Service,
- public ::bluetooth::hal::HciHalCallbacks {
-public:
- explicit HciHalFacadeService(HciHal* hal) : hal_(hal) {
- hal->registerIncomingPacketCallback(this);
- }
-
- ~HciHalFacadeService() { hal_->unregisterIncomingPacketCallback(); }
-
- ::grpc::Status SendCommand(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::Data* request,
- ::google::protobuf::Empty* /* response */) override {
- std::unique_lock<std::mutex> lock(mutex_);
- can_send_hci_command_ = false;
- std::string req_string = request->payload();
- hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
- while (!can_send_hci_command_) {
- cv_.wait(lock);
- }
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SendAcl(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::Data* request,
- ::google::protobuf::Empty* /* response */) override {
- std::string req_string = request->payload();
- hal_->sendAclData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SendSco(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::Data* request,
- ::google::protobuf::Empty* /* response */) override {
- std::string req_string = request->payload();
- hal_->sendScoData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status StreamEvents(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- return pending_hci_events_.RunLoop(context, writer);
- }
-
- ::grpc::Status StreamAcl(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- return pending_acl_events_.RunLoop(context, writer);
- }
-
- ::grpc::Status StreamSco(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- return pending_sco_events_.RunLoop(context, writer);
- }
-
- ::grpc::Status StreamIso(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- return pending_iso_events_.RunLoop(context, writer);
- }
-
- void hciEventReceived(bluetooth::hal::HciPacket event) override {
- {
- ::blueberry::facade::Data response;
- response.set_payload(std::string(event.begin(), event.end()));
- pending_hci_events_.OnIncomingEvent(std::move(response));
- }
- can_send_hci_command_ = true;
- cv_.notify_one();
- }
-
- void aclDataReceived(bluetooth::hal::HciPacket data) override {
- ::blueberry::facade::Data response;
- response.set_payload(std::string(data.begin(), data.end()));
- pending_acl_events_.OnIncomingEvent(std::move(response));
- }
-
- void scoDataReceived(bluetooth::hal::HciPacket data) override {
- ::blueberry::facade::Data response;
- response.set_payload(std::string(data.begin(), data.end()));
- pending_sco_events_.OnIncomingEvent(std::move(response));
- }
-
- void isoDataReceived(bluetooth::hal::HciPacket data) override {
- ::blueberry::facade::Data response;
- response.set_payload(std::string(data.begin(), data.end()));
- pending_iso_events_.OnIncomingEvent(std::move(response));
- }
-
-private:
- HciHal* hal_;
- bool can_send_hci_command_ = true;
- mutable std::mutex mutex_;
- std::condition_variable cv_;
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_hci_events_{"StreamEvents"};
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_acl_events_{"StreamAcl"};
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_sco_events_{"StreamSco"};
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_iso_events_{"StreamIso"};
-};
-
-void HciHalFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<HciHal>();
-}
-
-void HciHalFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new HciHalFacadeService(GetDependency<HciHal>());
-}
-
-void HciHalFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* HciHalFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory HciHalFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new HciHalFacadeModule(); });
-
-} // namespace hal
-} // namespace bluetooth
diff --git a/system/gd/hal/facade.h b/system/gd/hal/facade.h
deleted file mode 100644
index edf785631a..0000000000
--- a/system/gd/hal/facade.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include <list>
-#include <mutex>
-
-#include "grpc/grpc_module.h"
-#include "hal/hci_hal.h"
-
-namespace bluetooth {
-namespace hal {
-
-class HciHalFacadeService;
-
-class HciHalFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
-
- void Start() override;
- void Stop() override;
-
- ::grpc::Service* GetService() const override;
-
-private:
- HciHalFacadeService* service_;
-};
-
-} // namespace hal
-} // namespace bluetooth
diff --git a/system/gd/hal/ranging_hal.h b/system/gd/hal/ranging_hal.h
index 1d034ef69f..5a37900bc5 100644
--- a/system/gd/hal/ranging_hal.h
+++ b/system/gd/hal/ranging_hal.h
@@ -323,6 +323,7 @@ public:
virtual void WriteProcedureData(uint16_t connection_handle, hci::CsRole local_cs_role,
const ProcedureDataV2& procedure_data,
uint16_t procedure_counter) = 0;
+ virtual bool IsAbortedProcedureRequired(uint16_t connection_handle) = 0;
};
} // namespace hal
diff --git a/system/gd/hal/ranging_hal_android.cc b/system/gd/hal/ranging_hal_android.cc
index f73a9998df..d093685863 100644
--- a/system/gd/hal/ranging_hal_android.cc
+++ b/system/gd/hal/ranging_hal_android.cc
@@ -521,6 +521,25 @@ public:
}
}
+ bool IsAbortedProcedureRequired(uint16_t connection_handle) override {
+ auto it = session_trackers_.find(connection_handle);
+ if (it == session_trackers_.end()) {
+ log::error("Can't find session for connection_handle:0x{:04x}", connection_handle);
+ return false;
+ }
+ if (it->second->GetSession() == nullptr) {
+ log::error("Session not opened");
+ return false;
+ }
+ bool isRequired = false;
+ auto aidl_ret = it->second->GetSession()->isAbortedProcedureRequired(&isRequired);
+ if (aidl_ret.isOk()) {
+ return isRequired;
+ }
+ log::error("can not get result for isAbortedProcedureRequired.");
+ return false;
+ }
+
protected:
void ListDependencies(ModuleList* /*list*/) const {}
diff --git a/system/gd/hal/ranging_hal_host.cc b/system/gd/hal/ranging_hal_host.cc
index 0d8385f564..59282dc422 100644
--- a/system/gd/hal/ranging_hal_host.cc
+++ b/system/gd/hal/ranging_hal_host.cc
@@ -63,6 +63,8 @@ public:
void UpdateConnInterval(uint16_t /* connection_handle */, uint16_t /* conn_interval */) override {
}
+ bool IsAbortedProcedureRequired(uint16_t /*connection_handle*/) { return false; }
+
protected:
void ListDependencies(ModuleList* /*list*/) const {}
diff --git a/system/gd/hal/snoop_logger.cc b/system/gd/hal/snoop_logger.cc
index 84eb0302e5..2e587cbfd6 100644
--- a/system/gd/hal/snoop_logger.cc
+++ b/system/gd/hal/snoop_logger.cc
@@ -35,7 +35,6 @@
#include "common/strings.h"
#include "hal/snoop_logger_common.h"
#include "hci/hci_packets.h"
-#include "module_dumper_flatbuffer.h"
#include "os/files.h"
#include "os/parameter_provider.h"
#include "os/system_properties.h"
diff --git a/system/gd/hal/snoop_logger_test.cc b/system/gd/hal/snoop_logger_test.cc
index 380e68a0e5..bfe81f3194 100644
--- a/system/gd/hal/snoop_logger_test.cc
+++ b/system/gd/hal/snoop_logger_test.cc
@@ -129,7 +129,6 @@ public:
class SnoopLoggerModuleTest : public Test {
public:
- flatbuffers::FlatBufferBuilder* builder_;
TestModuleRegistry* test_registry;
protected:
@@ -149,7 +148,6 @@ protected:
temp_dir_ / (std::string(test_info->name()) + "_btsnoop_hci.log.filtered");
temp_snoop_log_filtered_last =
temp_dir_ / (std::string(test_info->name()) + "_btsnoop_hci.log.filtered.last");
- builder_ = new flatbuffers::FlatBufferBuilder();
DeleteSnoopLogFiles();
ASSERT_FALSE(std::filesystem::exists(temp_snoop_log_));
@@ -164,7 +162,6 @@ protected:
void TearDown() override {
DeleteSnoopLogFiles();
- delete builder_;
fake_timerfd_reset();
test_registry->StopAll();
delete test_registry;
diff --git a/system/gd/hal/socket_hal.h b/system/gd/hal/socket_hal.h
new file mode 100644
index 0000000000..3922e29da0
--- /dev/null
+++ b/system/gd/hal/socket_hal.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "module.h"
+
+namespace bluetooth::hal {
+
+enum SocketStatus {
+ SUCCESS = 0,
+ FAILURE,
+};
+
+struct EndpointInfo {
+ // The ID of the Hub to which the end point belongs for hardware offload data path.
+ uint64_t hub_id;
+
+ // The ID of the Hub endpoint for hardware offload data path.
+ uint64_t endpoint_id;
+};
+
+struct LeCocCapabilities {
+ // Maximum number of LE COC sockets supported. If not supported, the value must be zero.
+ int number_of_supported_sockets;
+
+ // Local Maximum Transmission Unit size in octets.
+ uint16_t mtu;
+};
+
+struct RfcommCapabilities {
+ // Maximum number of RFCOMM sockets supported. If not supported, the value must be zero.
+ int number_of_supported_sockets;
+
+ // Maximum frame size in octets negotiated during DLCI establishment.
+ uint16_t max_frame_size;
+};
+
+struct SocketCapabilities {
+ LeCocCapabilities le_coc_capabilities;
+ RfcommCapabilities rfcomm_capabilities;
+};
+
+struct LeCocChannelInfo {
+ // L2cap local channel ID.
+ uint16_t local_cid;
+
+ // L2cap remote channel ID.
+ uint16_t remote_cid;
+
+ // PSM for L2CAP LE CoC.
+ uint16_t psm;
+
+ // Local Maximum Transmission Unit for LE COC specifying the maximum SDU size in bytes that the
+ // local L2CAP layer can receive.
+ uint16_t local_mtu;
+
+ // Remote Maximum Transmission Unit for LE COC specifying the maximum SDU size in bytes that the
+ // remote L2CAP layer can receive.
+ uint16_t remote_mtu;
+
+ // Local Maximum PDU payload Size in bytes that the local L2CAP layer can receive.
+ uint16_t local_mps;
+
+ // Remote Maximum PDU payload Size in bytes that the remote L2CAP layer can receive.
+ uint16_t remote_mps;
+
+ // Protocol initial credits at Rx path.
+ uint16_t initial_rx_credits;
+
+ // Protocol initial credits at Tx path.
+ uint16_t initial_tx_credits;
+};
+
+struct RfcommChannelInfo {
+ // L2cap local channel ID for RFCOMM.
+ int local_cid;
+
+ // L2cap remote channel ID for RFCOMM.
+ int remote_cid;
+
+ // Local Maximum Transmission Unit Size in bytes that the local L2CAP layer can receive.
+ int local_mtu;
+
+ // Remote Maximum Transmission Unit Size in bytes that the remote L2CAP layer can receive.
+ int remote_mtu;
+
+ // Protocol initial credits at Rx path.
+ int initial_rx_credits;
+
+ // Protocol initial credits at Tx path.
+ int initial_tx_credits;
+
+ // Data Link Connection Identifier (DLCI).
+ int dlci;
+
+ // Maximum frame size negotiated during DLCI establishment.
+ int max_frame_size;
+
+ // Flag of whether the Android stack initiated the RFCOMM multiplexer control channel.
+ bool mux_initiator;
+};
+
+struct SocketContext {
+ // Identifier assigned to the socket by the host stack when the socket is connected.
+ uint64_t socket_id;
+
+ // Descriptive socket name provided by the host app when it created this socket.
+ std::string name;
+
+ // ACL connection handle for the socket.
+ uint16_t acl_connection_handle;
+
+ // Channel information of different protocol used for the socket.
+ std::variant<LeCocChannelInfo, RfcommChannelInfo> channel_info;
+
+ // Endpoint information.
+ EndpointInfo endpoint_info;
+};
+
+/**
+ * SocketHalCallback provides an interface for receiving asynchronous events from socket HAL.
+ * Implementations of this class can be registered with the stack to receive these callbacks.
+ *
+ * Callback methods in this interface are invoked from the binder thread. This means that
+ * implementations must be thread-safe and handle any necessary synchronization to avoid race
+ * conditions or other concurrency issues. The callee is solely responsible for ensuring thread
+ * safety within the callback methods.
+ */
+class SocketHalCallback {
+public:
+ virtual ~SocketHalCallback() = default;
+
+ /**
+ * Invoked when IBluetoothSocket.opened() has been completed.
+ *
+ * @param socket_id Identifier assigned to the socket by the host stack
+ * @param status Status indicating success or failure
+ */
+ virtual void SocketOpenedComplete(uint64_t socket_id, SocketStatus status) const = 0;
+
+ /**
+ * Invoked when offload app or stack requests host stack to close the socket.
+ *
+ * @param socket_id Identifier assigned to the socket by the host stack
+ */
+ virtual void SocketClose(uint64_t socket_id) const = 0;
+};
+
+/**
+ * SocketHal provides an interface to low-power processors, enabling Bluetooth Offload Socket
+ * functionality.
+ *
+ * Bluetooth Offload Socket allows the transfer of channel information from an established
+ * BluetoothSocket to a low-power processor. This enables the offload stack on the low-power
+ * processor to handle packet reception, processing, and transmission independently. This offloading
+ * process prevents the need to wake the main application processor, improving power efficiency.
+ */
+class SocketHal : public ::bluetooth::Module {
+public:
+ static const ModuleFactory Factory;
+
+ virtual ~SocketHal() = default;
+
+ /**
+ * Registers a socket hal callback function to receive asynchronous events from socket HAL.
+ *
+ * @param callback A pointer to the callback function. Must not be nullptr and must have static
+ * lifetime.
+ * @return True if the callback was successfully registered, false otherwise.
+ */
+ virtual bool RegisterCallback(hal::SocketHalCallback const* callback) = 0;
+
+ /**
+ * Retrieves the supported offloaded socket capabilities.
+ *
+ * @return Supported socket capabilities
+ */
+ virtual hal::SocketCapabilities GetSocketCapabilities() const = 0;
+
+ /**
+ * Notifies the socket HAL that the socket has been opened.
+ *
+ * @param context Socket context including socket ID, channel, hub, and endpoint info
+ * @return Result of calling this method
+ */
+ virtual bool Opened(const hal::SocketContext& context) const = 0;
+
+ /**
+ * Notifies the socket HAL that the socket has been closed.
+ *
+ * @param socket_id Identifier assigned to the socket by the host stack
+ */
+ virtual void Closed(uint64_t socket_id) const = 0;
+};
+
+} // namespace bluetooth::hal
diff --git a/system/gd/hal/socket_hal_android.cc b/system/gd/hal/socket_hal_android.cc
new file mode 100644
index 0000000000..4974efb0cf
--- /dev/null
+++ b/system/gd/hal/socket_hal_android.cc
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/bluetooth/socket/BnBluetoothSocketCallback.h>
+#include <aidl/android/hardware/bluetooth/socket/IBluetoothSocket.h>
+#include <aidl/android/hardware/bluetooth/socket/IBluetoothSocketCallback.h>
+#include <android/binder_manager.h>
+#include <bluetooth/log.h>
+
+// syslog.h conflicts with libchrome/base/logging.h
+#undef LOG_DEBUG
+#undef LOG_INFO
+#undef LOG_WARNING
+
+#include "hal/socket_hal.h"
+
+using ::aidl::android::hardware::bluetooth::socket::BnBluetoothSocketCallback;
+using ::aidl::android::hardware::bluetooth::socket::IBluetoothSocket;
+
+namespace bluetooth::hal {
+
+constexpr uint16_t kLeCocMtuMin = 23;
+constexpr uint16_t kLeCocMtuMax = 65535;
+constexpr uint16_t kRfcommFrameSizeMin = 23;
+constexpr uint16_t kRfcommFrameSizeMax = 32767;
+
+class SocketAidlCallback : public BnBluetoothSocketCallback {
+ class : public hal::SocketHalCallback {
+ public:
+ void SocketOpenedComplete(uint64_t /* socket_id */,
+ hal::SocketStatus /* status */) const override {
+ log::warn("Dropping SocketOpenedComplete event, since callback is not set");
+ }
+
+ void SocketClose(uint64_t /* socket_id */) const override {
+ log::warn("Dropping SocketClose event, since callback is not set");
+ }
+ } kNullCallbacks;
+
+public:
+ SocketAidlCallback() = default;
+
+ void SetCallback(hal::SocketHalCallback const* callback) {
+ log::assert_that(callback != nullptr, "callback != nullptr");
+ socket_hal_cb_ = callback;
+ }
+
+ ::ndk::ScopedAStatus openedComplete(int64_t socket_id,
+ ::aidl::android::hardware::bluetooth::socket::Status status,
+ const std::string& reason) override {
+ log::info("socket_id: {} status: {} reason: {}", socket_id, static_cast<int>(status), reason);
+ socket_hal_cb_->SocketOpenedComplete(
+ socket_id, status == ::aidl::android::hardware::bluetooth::socket::Status::SUCCESS
+ ? hal::SocketStatus::SUCCESS
+ : hal::SocketStatus::FAILURE);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ ::ndk::ScopedAStatus close(int64_t socket_id, const std::string& reason) override {
+ log::info("socket_id: {} reason: {}", socket_id, reason);
+ socket_hal_cb_->SocketClose(socket_id);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+private:
+ hal::SocketHalCallback const* socket_hal_cb_ = &kNullCallbacks;
+};
+
+class SocketHalAndroid : public SocketHal {
+public:
+ bool IsBound() const { return socket_hal_instance_ != nullptr; }
+
+protected:
+ void ListDependencies(ModuleList* /*list*/) const {}
+
+ void Start() override {
+ std::string instance = std::string() + IBluetoothSocket::descriptor + "/default";
+ if (!AServiceManager_isDeclared(instance.c_str())) {
+ log::error("The service {} is not declared", instance);
+ return;
+ }
+
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(instance.c_str()));
+ socket_hal_instance_ = IBluetoothSocket::fromBinder(binder);
+
+ if (socket_hal_instance_ == nullptr) {
+ log::error("Failed to bind to the service {}", instance);
+ return;
+ }
+
+ socket_aidl_cb_ = ndk::SharedRefBase::make<SocketAidlCallback>();
+ ::ndk::ScopedAStatus status = socket_hal_instance_->registerCallback(socket_aidl_cb_);
+ if (!status.isOk()) {
+ log::error("registerCallback failure: {}", status.getDescription());
+ socket_hal_instance_ = nullptr;
+ return;
+ }
+
+ death_recipient_ =
+ ::ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new([](void* /* cookie*/) {
+ log::error("The Socket HAL service died.");
+ // At shutdown, sometimes the HAL service gets killed before Bluetooth.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ log::fatal("Restarting Bluetooth after the socket HAL has died.");
+ }));
+
+ auto death_link = AIBinder_linkToDeath(socket_hal_instance_->asBinder().get(),
+ death_recipient_.get(), this);
+ log::assert_that(death_link == STATUS_OK,
+ "Unable to set the death recipient for the Socket HAL");
+ }
+
+ void Stop() override {
+ if (IsBound()) {
+ auto death_unlink = AIBinder_unlinkToDeath(socket_hal_instance_->asBinder().get(),
+ death_recipient_.get(), this);
+ if (death_unlink != STATUS_OK) {
+ log::error("Error unlinking death recipient from the Socket HAL");
+ }
+ socket_hal_instance_ = nullptr;
+ }
+ }
+
+ std::string ToString() const override { return std::string("SocketHalAndroid"); }
+
+ hal::SocketCapabilities GetSocketCapabilities() const override {
+ if (!IsBound()) {
+ return {};
+ }
+ ::aidl::android::hardware::bluetooth::socket::SocketCapabilities socket_capabilities;
+ ::ndk::ScopedAStatus status = socket_hal_instance_->getSocketCapabilities(&socket_capabilities);
+ if (!status.isOk()) {
+ log::info("Failed to get socket capabilities");
+ return {};
+ }
+ if (socket_capabilities.leCocCapabilities.numberOfSupportedSockets < 0) {
+ log::error("Invalid leCocCapabilities.numberOfSupportedSockets: {}",
+ socket_capabilities.leCocCapabilities.numberOfSupportedSockets);
+ return {};
+ }
+ if (socket_capabilities.leCocCapabilities.numberOfSupportedSockets) {
+ if (socket_capabilities.leCocCapabilities.mtu < kLeCocMtuMin ||
+ socket_capabilities.leCocCapabilities.mtu > kLeCocMtuMax) {
+ log::error("Invalid leCocCapabilities.mtu: {}", socket_capabilities.leCocCapabilities.mtu);
+ return {};
+ }
+ }
+ log::info("le_coc_capabilities number_of_supported_sockets: {}, mtu: {}",
+ socket_capabilities.leCocCapabilities.numberOfSupportedSockets,
+ socket_capabilities.leCocCapabilities.mtu);
+
+ if (socket_capabilities.rfcommCapabilities.numberOfSupportedSockets < 0) {
+ log::error("Invalid rfcommCapabilities.numberOfSupportedSockets: {}",
+ socket_capabilities.rfcommCapabilities.numberOfSupportedSockets);
+ return {};
+ }
+ if (socket_capabilities.rfcommCapabilities.numberOfSupportedSockets) {
+ if (socket_capabilities.rfcommCapabilities.maxFrameSize < kRfcommFrameSizeMin ||
+ socket_capabilities.rfcommCapabilities.maxFrameSize > kRfcommFrameSizeMax) {
+ log::error("Invalid rfcommCapabilities.maxFrameSize: {}",
+ socket_capabilities.rfcommCapabilities.maxFrameSize);
+ return {};
+ }
+ }
+ log::info("rfcomm_capabilities number_of_supported_sockets: {}, max_frame_size: {}",
+ socket_capabilities.rfcommCapabilities.numberOfSupportedSockets,
+ socket_capabilities.rfcommCapabilities.maxFrameSize);
+
+ return hal::SocketCapabilities{
+ .le_coc_capabilities.number_of_supported_sockets =
+ socket_capabilities.leCocCapabilities.numberOfSupportedSockets,
+ .le_coc_capabilities.mtu =
+ static_cast<uint16_t>(socket_capabilities.leCocCapabilities.mtu),
+ .rfcomm_capabilities.number_of_supported_sockets =
+ socket_capabilities.rfcommCapabilities.numberOfSupportedSockets,
+ .rfcomm_capabilities.max_frame_size =
+ static_cast<uint16_t>(socket_capabilities.rfcommCapabilities.maxFrameSize)};
+ }
+
+ bool RegisterCallback(hal::SocketHalCallback const* callback) override {
+ if (!IsBound()) {
+ return false;
+ }
+ socket_aidl_cb_->SetCallback(callback);
+ return true;
+ }
+
+ bool Opened(const hal::SocketContext& context) const override {
+ if (!IsBound()) {
+ return false;
+ }
+ log::info("socket_id: {}, name: {}, acl_connection_handle: {}, hub_id: {}, endpoint_id: {}",
+ context.socket_id, context.name, context.acl_connection_handle,
+ context.endpoint_info.hub_id, context.endpoint_info.endpoint_id);
+ ::aidl::android::hardware::bluetooth::socket::SocketContext hal_context = {
+ .socketId = static_cast<int64_t>(context.socket_id),
+ .name = context.name,
+ .aclConnectionHandle = context.acl_connection_handle,
+ .endpointId.id = static_cast<int64_t>(context.endpoint_info.endpoint_id),
+ .endpointId.hubId = static_cast<int64_t>(context.endpoint_info.hub_id),
+ };
+ if (std::holds_alternative<hal::LeCocChannelInfo>(context.channel_info)) {
+ auto& le_coc_context = std::get<hal::LeCocChannelInfo>(context.channel_info);
+ hal_context.channelInfo = ::aidl::android::hardware::bluetooth::socket::LeCocChannelInfo(
+ le_coc_context.local_cid, le_coc_context.remote_cid, le_coc_context.psm,
+ le_coc_context.local_mtu, le_coc_context.remote_mtu, le_coc_context.local_mps,
+ le_coc_context.remote_mps, le_coc_context.initial_rx_credits,
+ le_coc_context.initial_tx_credits);
+ log::info(
+ "le_coc local_cid: {}, remote_cid: {}, psm: {}, local_mtu: {}, remote_mtu: {}, "
+ "local_mps: {}, remote_mps: {}, initial_rx_credits: {}, initial_tx_credits: {}",
+ le_coc_context.local_cid, le_coc_context.remote_cid, le_coc_context.psm,
+ le_coc_context.local_mtu, le_coc_context.remote_mtu, le_coc_context.local_mps,
+ le_coc_context.remote_mps, le_coc_context.initial_rx_credits,
+ le_coc_context.initial_tx_credits);
+ } else if (std::holds_alternative<hal::RfcommChannelInfo>(context.channel_info)) {
+ auto& rfcomm_context = std::get<hal::RfcommChannelInfo>(context.channel_info);
+ hal_context.channelInfo = ::aidl::android::hardware::bluetooth::socket::RfcommChannelInfo(
+ rfcomm_context.local_cid, rfcomm_context.remote_cid, rfcomm_context.local_mtu,
+ rfcomm_context.remote_mtu, rfcomm_context.initial_rx_credits,
+ rfcomm_context.initial_tx_credits, rfcomm_context.dlci, rfcomm_context.max_frame_size,
+ rfcomm_context.mux_initiator);
+ log::info(
+ "rfcomm local_cid: {}, remote_cid: {}, local_mtu: {}, remote_mtu: {}, "
+ "initial_rx_credits: {}, initial_tx_credits: {}, dlci: {}, max_frame_size: {}, "
+ "mux_initiator: {}",
+ rfcomm_context.local_cid, rfcomm_context.remote_cid, rfcomm_context.local_mtu,
+ rfcomm_context.remote_mtu, rfcomm_context.initial_rx_credits,
+ rfcomm_context.initial_tx_credits, rfcomm_context.dlci, rfcomm_context.max_frame_size,
+ rfcomm_context.mux_initiator);
+ } else {
+ log::error("Unsupported protocol");
+ return false;
+ }
+ ::ndk::ScopedAStatus status = socket_hal_instance_->opened(hal_context);
+ if (!status.isOk()) {
+ log::error("Opened failure: {}", status.getDescription());
+ return false;
+ }
+ return true;
+ }
+
+ void Closed(uint64_t socket_id) const override {
+ if (!IsBound()) {
+ return;
+ }
+ log::info("socket_id: {}", socket_id);
+ ::ndk::ScopedAStatus status = socket_hal_instance_->closed(socket_id);
+ if (!status.isOk()) {
+ log::info("Closed failure: {}", status.getDescription());
+ }
+ }
+
+private:
+ std::shared_ptr<IBluetoothSocket> socket_hal_instance_;
+ std::shared_ptr<SocketAidlCallback> socket_aidl_cb_;
+ ::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
+};
+
+const ModuleFactory SocketHal::Factory = ModuleFactory([]() { return new SocketHalAndroid(); });
+
+} // namespace bluetooth::hal
diff --git a/system/gd/hal/socket_hal_host.cc b/system/gd/hal/socket_hal_host.cc
new file mode 100644
index 0000000000..292428a821
--- /dev/null
+++ b/system/gd/hal/socket_hal_host.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "hal/socket_hal.h"
+
+namespace bluetooth::hal {
+
+class SocketHalHost : public SocketHal {
+protected:
+ void ListDependencies(ModuleList* /*list*/) const {}
+
+ void Start() override {}
+
+ void Stop() override { socket_hal_cb_ = nullptr; }
+
+ std::string ToString() const override { return std::string("SocketHalHost"); }
+
+ hal::SocketCapabilities GetSocketCapabilities() const override { return {}; }
+
+ bool RegisterCallback(hal::SocketHalCallback const* /*callback*/) override { return false; }
+
+ bool Opened(const hal::SocketContext& /*context*/) const override { return false; }
+
+ void Closed(uint64_t /*socket_id*/) const override {}
+
+private:
+ hal::SocketHalCallback* socket_hal_cb_;
+};
+
+const ModuleFactory SocketHal::Factory = ModuleFactory([]() { return new SocketHalHost(); });
+
+} // namespace bluetooth::hal
diff --git a/system/gd/hci/Android.bp b/system/gd/hci/Android.bp
index d0fc019dd5..b0c7f04510 100644
--- a/system/gd/hci/Android.bp
+++ b/system/gd/hci/Android.bp
@@ -72,19 +72,6 @@ filegroup {
}
filegroup {
- name: "BluetoothFacade_hci_layer",
- srcs: [
- "facade/acl_manager_facade.cc",
- "facade/controller_facade.cc",
- "facade/facade.cc",
- "facade/le_acl_manager_facade.cc",
- "facade/le_advertising_manager_facade.cc",
- "facade/le_initiator_address_facade.cc",
- "facade/le_scanning_manager_facade.cc",
- ],
-}
-
-filegroup {
name: "BluetoothHciFuzzTestSources",
srcs: [
"hci_packets_fuzz_test.cc",
diff --git a/system/gd/hci/acl_manager.cc b/system/gd/hci/acl_manager.cc
index 682800522c..869865e2c2 100644
--- a/system/gd/hci/acl_manager.cc
+++ b/system/gd/hci/acl_manager.cc
@@ -29,7 +29,6 @@
#include "common/bidi_queue.h"
#include "common/byte_array.h"
-#include "dumpsys_data_generated.h"
#include "hci/acl_manager/acl_scheduler.h"
#include "hci/acl_manager/classic_impl.h"
#include "hci/acl_manager/le_acceptlist_callbacks.h"
@@ -85,7 +84,7 @@ struct AclManager::impl {
crash_on_unknown_handle, acl_scheduler_,
remote_name_request_module_);
le_impl_ = new le_impl(hci_layer_, controller_, handler_, round_robin_scheduler_,
- crash_on_unknown_handle);
+ crash_on_unknown_handle, classic_impl_);
}
hci_queue_end_ = hci_layer_->GetAclQueueEnd();
diff --git a/system/gd/hci/acl_manager/acl_scheduler.cc b/system/gd/hci/acl_manager/acl_scheduler.cc
index 9b12f4b4e7..320373593b 100644
--- a/system/gd/hci/acl_manager/acl_scheduler.cc
+++ b/system/gd/hci/acl_manager/acl_scheduler.cc
@@ -215,7 +215,7 @@ private:
const std::string set_of_incoming_connecting_addresses() const {
std::stringstream buffer;
for (const auto& c : incoming_connecting_address_set_) {
- buffer << " " << c;
+ buffer << " " << c.ToRedactedStringForLogging();
}
return buffer.str();
}
diff --git a/system/gd/hci/acl_manager/classic_acl_connection.cc b/system/gd/hci/acl_manager/classic_acl_connection.cc
index a2b6b9e30e..301211c345 100644
--- a/system/gd/hci/acl_manager/classic_acl_connection.cc
+++ b/system/gd/hci/acl_manager/classic_acl_connection.cc
@@ -17,6 +17,7 @@
#include "hci/acl_manager/classic_acl_connection.h"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include "hci/address.h"
#include "hci/event_checkers.h"
@@ -377,6 +378,14 @@ void ClassicAclConnection::RegisterCallbacks(ConnectionManagementCallbacks* call
}
bool ClassicAclConnection::Disconnect(DisconnectReason reason) {
+ if (com::android::bluetooth::flags::dont_send_hci_disconnect_repeatedly()) {
+ if (is_disconnecting_) {
+ log::info("Already disconnecting {}", address_);
+ return true;
+ }
+ }
+
+ is_disconnecting_ = true;
acl_connection_interface_->EnqueueCommand(
DisconnectBuilder::Create(handle_, reason),
pimpl_->tracker.client_handler_->BindOnce(check_status<DisconnectStatusView>));
diff --git a/system/gd/hci/acl_manager/classic_acl_connection.h b/system/gd/hci/acl_manager/classic_acl_connection.h
index a92761b770..75dacf52d1 100644
--- a/system/gd/hci/acl_manager/classic_acl_connection.h
+++ b/system/gd/hci/acl_manager/classic_acl_connection.h
@@ -83,6 +83,7 @@ public:
private:
AclConnectionInterface* acl_connection_interface_;
+ bool is_disconnecting_ = false;
protected:
Address address_;
diff --git a/system/gd/hci/acl_manager/classic_acl_connection_test.cc b/system/gd/hci/acl_manager/classic_acl_connection_test.cc
index 85a206df27..32949927e7 100644
--- a/system/gd/hci/acl_manager/classic_acl_connection_test.cc
+++ b/system/gd/hci/acl_manager/classic_acl_connection_test.cc
@@ -283,33 +283,31 @@ TEST_F(ClassicAclConnectionTest, simple) {
class ClassicAclConnectionWithCallbacksTest : public ClassicAclConnectionTest {
protected:
- void SetUp() override {
- ClassicAclConnectionTest::SetUp();
+ void SetUpConnection() {
connection_ = std::make_unique<ClassicAclConnection>(queue_, &acl_connection_interface_,
kConnectionHandle, address_);
connection_->RegisterCallbacks(&callbacks_, handler_);
- is_callbacks_registered_ = true;
connection_management_callbacks_ = connection_->GetEventCallbacks(
[this](uint16_t /* hci_handle */) { is_callbacks_invalidated_ = true; });
is_callbacks_invalidated_ = false;
}
- void TearDown() override {
+ void CleanConnection() {
connection_.reset();
ASSERT_TRUE(is_callbacks_invalidated_);
- ClassicAclConnectionTest::TearDown();
}
protected:
std::unique_ptr<ClassicAclConnection> connection_;
ConnectionManagementCallbacks* connection_management_callbacks_;
- bool is_callbacks_registered_{false};
bool is_callbacks_invalidated_{false};
};
TEST_F(ClassicAclConnectionWithCallbacksTest, Disconnect) {
for (const auto& reason : disconnect_reason_vector) {
+ SetUpConnection();
ASSERT_TRUE(connection_->Disconnect(reason));
+ CleanConnection();
}
for (const auto& reason : disconnect_reason_vector) {
@@ -324,7 +322,9 @@ TEST_F(ClassicAclConnectionWithCallbacksTest, Disconnect) {
TEST_F(ClassicAclConnectionWithCallbacksTest, OnDisconnection) {
for (const auto& error_code : error_code_vector) {
+ SetUpConnection();
connection_management_callbacks_->OnDisconnection(error_code);
+ CleanConnection();
}
sync_handler();
diff --git a/system/gd/hci/acl_manager/classic_impl.h b/system/gd/hci/acl_manager/classic_impl.h
index 08cdcbd231..ecef1f9414 100644
--- a/system/gd/hci/acl_manager/classic_impl.h
+++ b/system/gd/hci/acl_manager/classic_impl.h
@@ -159,6 +159,10 @@ private:
public:
bool crash_on_unknown_handle_ = false;
+ size_t size() const {
+ std::unique_lock<std::mutex> lock(acl_connections_guard_);
+ return acl_connections_.size();
+ }
bool is_empty() const {
std::unique_lock<std::mutex> lock(acl_connections_guard_);
return acl_connections_.empty();
@@ -278,6 +282,8 @@ public:
return connections.is_classic_link_already_connected(address);
}
+ size_t get_connection_count() { return connections.size(); }
+
void create_connection(Address address) {
// TODO: Configure default connection parameters?
uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */;
diff --git a/system/gd/hci/acl_manager/le_acl_connection.cc b/system/gd/hci/acl_manager/le_acl_connection.cc
index 635c05b41b..8e6f93be08 100644
--- a/system/gd/hci/acl_manager/le_acl_connection.cc
+++ b/system/gd/hci/acl_manager/le_acl_connection.cc
@@ -17,6 +17,7 @@
#include "hci/acl_manager/le_acl_connection.h"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include "hci/acl_manager/le_connection_management_callbacks.h"
#include "hci/event_checkers.h"
@@ -186,6 +187,14 @@ void LeAclConnection::RegisterCallbacks(LeConnectionManagementCallbacks* callbac
}
void LeAclConnection::Disconnect(DisconnectReason reason) {
+ if (com::android::bluetooth::flags::dont_send_hci_disconnect_repeatedly()) {
+ if (is_disconnecting_) {
+ log::info("Already disconnecting {}", remote_address_);
+ return;
+ }
+ }
+
+ is_disconnecting_ = true;
pimpl_->tracker.le_acl_connection_interface_->EnqueueCommand(
DisconnectBuilder::Create(handle_, reason),
pimpl_->tracker.client_handler_->BindOnce([](CommandStatusView status) {
diff --git a/system/gd/hci/acl_manager/le_acl_connection.h b/system/gd/hci/acl_manager/le_acl_connection.h
index 574b104a97..5052be51a7 100644
--- a/system/gd/hci/acl_manager/le_acl_connection.h
+++ b/system/gd/hci/acl_manager/le_acl_connection.h
@@ -147,6 +147,7 @@ private:
virtual bool check_connection_parameters(uint16_t conn_interval_min, uint16_t conn_interval_max,
uint16_t expected_conn_latency,
uint16_t expected_supervision_timeout);
+ bool is_disconnecting_ = false;
struct impl;
struct impl* pimpl_ = nullptr;
};
diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h
index 9a0be0814f..95e3db16ca 100644
--- a/system/gd/hci/acl_manager/le_impl.h
+++ b/system/gd/hci/acl_manager/le_impl.h
@@ -16,7 +16,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -27,7 +26,9 @@
#include <vector>
#include "common/bind.h"
+#include "common/le_conn_params.h"
#include "hci/acl_manager/assembler.h"
+#include "hci/acl_manager/classic_impl.h"
#include "hci/acl_manager/le_acceptlist_callbacks.h"
#include "hci/acl_manager/le_acl_connection.h"
#include "hci/acl_manager/le_connection_callbacks.h"
@@ -41,6 +42,8 @@
#include "os/alarm.h"
#include "os/handler.h"
#include "os/system_properties.h"
+#include "stack/include/btm_ble_api_types.h"
+#include "stack/include/stack_metrics_logging.h"
namespace bluetooth {
namespace hci {
@@ -101,6 +104,8 @@ enum class ConnectabilityState {
DISARMING = 3,
};
+enum class ConnectionMode { RELAXED = 0, AGGRESSIVE = 1 };
+
inline std::string connectability_state_machine_text(const ConnectabilityState& state) {
switch (state) {
CASE_RETURN_TEXT(ConnectabilityState::DISARMED);
@@ -126,7 +131,8 @@ struct le_acl_connection {
struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
le_impl(HciLayer* hci_layer, Controller* controller, os::Handler* handler,
- RoundRobinScheduler* round_robin_scheduler, bool crash_on_unknown_handle)
+ RoundRobinScheduler* round_robin_scheduler, bool crash_on_unknown_handle,
+ classic_impl* classic_impl)
: hci_layer_(hci_layer),
controller_(controller),
round_robin_scheduler_(round_robin_scheduler) {
@@ -134,6 +140,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
controller_ = controller;
handler_ = handler;
connections.crash_on_unknown_handle_ = crash_on_unknown_handle;
+ classic_impl_ = classic_impl;
le_acl_connection_interface_ = hci_layer_->GetLeAclConnectionInterface(
handler_->BindOn(this, &le_impl::on_le_event),
handler_->BindOn(this, &le_impl::on_le_disconnect),
@@ -203,6 +210,10 @@ private:
public:
bool crash_on_unknown_handle_ = false;
+ size_t size() const {
+ std::unique_lock<std::mutex> lock(le_acl_connections_guard_);
+ return le_acl_connections_.size();
+ }
bool is_empty() const {
std::unique_lock<std::mutex> lock(le_acl_connections_guard_);
return le_acl_connections_.empty();
@@ -300,6 +311,17 @@ private:
}
} connections;
+ std::string connection_mode_to_string(ConnectionMode connection_mode) {
+ switch (connection_mode) {
+ case ConnectionMode::RELAXED:
+ return "RELAXED";
+ case ConnectionMode::AGGRESSIVE:
+ return "AGGRESSIVE";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
public:
void enqueue_command(std::unique_ptr<CommandBuilder> command_packet) {
hci_layer_->EnqueueCommand(std::move(command_packet),
@@ -404,6 +426,8 @@ public:
return;
}
+ log_le_connection_status(address, true /* is_connect */, status);
+
const bool in_filter_accept_list = is_device_in_accept_list(remote_address);
if (role == hci::Role::CENTRAL) {
@@ -487,6 +511,8 @@ public:
connection->in_filter_accept_list_ = in_filter_accept_list;
connection->locally_initiated_ = (role == hci::Role::CENTRAL);
+ log::info("addr={}, conn_interval={}", remote_address, conn_interval);
+
if (packet.GetSubeventCode() == SubeventCode::ENHANCED_CONNECTION_COMPLETE) {
LeEnhancedConnectionCompleteView connection_complete =
LeEnhancedConnectionCompleteView::Create(packet);
@@ -560,6 +586,7 @@ public:
arm_on_resume_ = true;
add_device_to_accept_list(remote_address);
}
+ log_le_connection_status(remote_address.GetAddress(), false /* is_connect */, reason);
}
void on_le_connection_update_complete(LeMetaEventView view) {
@@ -697,6 +724,7 @@ public:
}
void add_device_to_accept_list(AddressWithType address_with_type) {
+ log_le_device_in_accept_list(address_with_type.GetAddress(), true /* is_add */);
if (connections.alreadyConnected(address_with_type)) {
log::info("Device already connected, return");
return;
@@ -719,6 +747,7 @@ public:
}
void remove_device_from_accept_list(AddressWithType address_with_type) {
+ log_le_device_in_accept_list(address_with_type.GetAddress(), false /* is_add */);
if (accept_list.find(address_with_type) == accept_list.end()) {
log::warn("Device not in acceptlist and cannot be removed: {}", address_with_type);
return;
@@ -839,10 +868,24 @@ public:
InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST;
OwnAddressType own_address_type = static_cast<OwnAddressType>(
le_address_manager_->GetInitiatorAddress().GetAddressType());
- uint16_t conn_interval_min =
- os::GetSystemPropertyUint32(kPropertyMinConnInterval, kConnIntervalMin);
- uint16_t conn_interval_max =
- os::GetSystemPropertyUint32(kPropertyMaxConnInterval, kConnIntervalMax);
+
+ uint16_t conn_interval_min;
+ uint16_t conn_interval_max;
+
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ size_t num_classic_acl_connections = classic_impl_->get_connection_count();
+ size_t num_acl_connections = connections.size();
+
+ log::debug("ACL connection count: Classic={}, LE={}", num_classic_acl_connections,
+ num_acl_connections);
+
+ choose_connection_mode(num_classic_acl_connections + num_acl_connections, &conn_interval_min,
+ &conn_interval_max);
+ } else {
+ conn_interval_min = os::GetSystemPropertyUint32(kPropertyMinConnInterval, kConnIntervalMin);
+ conn_interval_max = os::GetSystemPropertyUint32(kPropertyMaxConnInterval, kConnIntervalMax);
+ }
+
uint16_t conn_latency = os::GetSystemPropertyUint32(kPropertyConnLatency, kConnLatency);
uint16_t supervision_timeout =
os::GetSystemPropertyUint32(kPropertyConnSupervisionTimeout, kSupervisionTimeout);
@@ -857,8 +900,7 @@ public:
address_with_type = AddressWithType();
}
- if (com::android::bluetooth::flags::rpa_offload_to_bt_controller() &&
- controller_->IsSupported(OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2) &&
+ if (controller_->IsRpaGenerationSupported() &&
own_address_type != OwnAddressType::PUBLIC_DEVICE_ADDRESS) {
log::info("Support RPA offload, set own address type RESOLVABLE_OR_RANDOM_ADDRESS");
own_address_type = OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS;
@@ -925,6 +967,36 @@ public:
}
}
+ // Choose which connection mode should be used based on the number of ongoing ACL connections.
+ // According to the connection mode, connection interval min/max values are set.
+ void choose_connection_mode(size_t num_acl_connections, uint16_t* conn_interval_min,
+ uint16_t* conn_interval_max) {
+ ConnectionMode connection_mode = ConnectionMode::RELAXED;
+
+ uint32_t aggressive_connection_threshold = LeConnectionParameters::GetAggressiveConnThreshold();
+ log::debug("num_acl_connections={}, aggressive_connection_threshold={}", num_acl_connections,
+ aggressive_connection_threshold);
+
+ if (num_acl_connections < aggressive_connection_threshold) {
+ connection_mode = ConnectionMode::AGGRESSIVE;
+ }
+
+ switch (connection_mode) {
+ case ConnectionMode::AGGRESSIVE:
+ *conn_interval_min = LeConnectionParameters::GetMinConnIntervalAggressive();
+ *conn_interval_max = LeConnectionParameters::GetMaxConnIntervalAggressive();
+ break;
+ case ConnectionMode::RELAXED:
+ default:
+ *conn_interval_min = LeConnectionParameters::GetMinConnIntervalRelaxed();
+ *conn_interval_max = LeConnectionParameters::GetMaxConnIntervalRelaxed();
+ break;
+ }
+ log::info("Connection mode: {}", connection_mode_to_string(connection_mode));
+ log::debug("conn_interval_min={}, conn_interval_max={}", *conn_interval_min,
+ *conn_interval_max);
+ }
+
void disarm_connectability() {
switch (connectability_state_) {
case ConnectabilityState::ARMED:
@@ -1232,6 +1304,7 @@ public:
RoundRobinScheduler* round_robin_scheduler_ = nullptr;
LeAddressManager* le_address_manager_ = nullptr;
LeAclConnectionInterface* le_acl_connection_interface_ = nullptr;
+ classic_impl* classic_impl_ = nullptr;
LeConnectionCallbacks* le_client_callbacks_ = nullptr;
os::Handler* le_client_handler_ = nullptr;
LeAcceptlistCallbacks* le_acceptlist_callbacks_ = nullptr;
diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc
index 5a5f15676c..d43d2faca1 100644
--- a/system/gd/hci/acl_manager/le_impl_test.cc
+++ b/system/gd/hci/acl_manager/le_impl_test.cc
@@ -26,6 +26,7 @@
#include <future>
#include "common/bidi_queue.h"
+#include "common/le_conn_params.h"
#include "hci/acl_manager/le_connection_callbacks.h"
#include "hci/acl_manager/le_connection_management_callbacks_mock.h"
#include "hci/address_with_type.h"
@@ -36,6 +37,7 @@
#include "os/handler.h"
#include "packet/bit_inserter.h"
#include "packet/raw_builder.h"
+#include "stack/l2cap/l2c_api.h"
using namespace bluetooth;
using namespace std::chrono_literals;
@@ -248,8 +250,11 @@ protected:
round_robin_scheduler_ = new RoundRobinScheduler(handler_, controller_, hci_queue_.GetUpEnd());
hci_queue_.GetDownEnd()->RegisterDequeue(
handler_, common::Bind(&LeImplTest::HciDownEndDequeue, common::Unretained(this)));
+
+ classic_impl_ = new classic_impl(hci_layer_, controller_, handler_, round_robin_scheduler_,
+ false, nullptr, nullptr);
le_impl_ = new le_impl(hci_layer_, controller_, handler_, round_robin_scheduler_,
- kCrashOnUnknownHandle);
+ kCrashOnUnknownHandle, classic_impl_);
le_impl_->handle_register_le_callbacks(&mock_le_connection_callbacks_, handler_);
Address address;
@@ -437,6 +442,69 @@ protected:
ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
}
+ // Need to store the LeAclConnection so it is not immediately dropped => disconnected
+ std::unique_ptr<LeAclConnection> create_enhanced_connection(std::string remote_address_string,
+ int handle) {
+ std::unique_ptr<LeAclConnection> connection;
+
+ hci::Address remote_address;
+ Address::FromString(remote_address_string, remote_address);
+ hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
+ le_impl_->create_le_connection(address_with_type, true, false);
+ sync_handler();
+
+ hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ hci_layer_->IncomingEvent(
+ LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
+ hci_layer_->IncomingEvent(
+ LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+ sync_handler();
+
+ // Check state is ARMED
+ EXPECT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
+
+ // we need to capture the LeAclConnection so it is not immediately dropped => disconnected
+ EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _))
+ .WillOnce([&](AddressWithType, std::unique_ptr<LeAclConnection> conn) {
+ connection = std::move(conn);
+ connection->RegisterCallbacks(&connection_management_callbacks_, handler_);
+ });
+
+ hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, handle, Role::CENTRAL, AddressType::PUBLIC_DEVICE_ADDRESS,
+ remote_address, Address::kEmpty, Address::kEmpty, 0x0024, 0x0000, 0x0011,
+ ClockAccuracy::PPM_30));
+ sync_handler();
+
+ hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+ hci_layer_->IncomingEvent(
+ LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ hci_layer_->AssertNoQueuedCommand();
+ sync_handler();
+ EXPECT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
+
+ return connection;
+ }
+
+ LeExtendedCreateConnectionView get_view_from_creating_connection(
+ std::string remote_address_string) {
+ hci::Address remote_address;
+ Address::FromString(remote_address_string, remote_address);
+ hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
+
+ // Create connection
+ le_impl_->create_le_connection(address_with_type, true, false);
+
+ hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+ hci_layer_->IncomingEvent(
+ LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+ sync_handler();
+
+ return CreateLeConnectionManagementCommandView<LeExtendedCreateConnectionView>(
+ hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION));
+ }
+
void TearDown() override {
com::android::bluetooth::flags::provider_->reset_flags();
@@ -450,6 +518,7 @@ protected:
sync_handler();
delete le_impl_;
+ delete classic_impl_;
hci_queue_.GetDownEnd()->UnregisterDequeue();
@@ -511,6 +580,7 @@ protected:
Thread* thread_;
Handler* handler_;
HciLayerFake* hci_layer_{nullptr};
+ classic_impl* classic_impl_;
TestController* controller_;
RoundRobinScheduler* round_robin_scheduler_{nullptr};
@@ -746,6 +816,72 @@ TEST_F(LeImplTest, enhanced_connection_complete_with_central_role) {
ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
}
+TEST_F(LeImplTest, aggressive_connection_mode_selected_when_no_ongoing_le_connections_exist) {
+ if (LeConnectionParameters::GetAggressiveConnThreshold() == 0) {
+ GTEST_SKIP() << "Skipping test because the threshold is zero";
+ }
+
+ com::android::bluetooth::flags::provider_->initial_conn_params_p1(true);
+ set_random_device_address_policy();
+ controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
+
+ LeExtendedCreateConnectionView view = get_view_from_creating_connection("FF:EE:DD:CC:BB:AA");
+
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_min_,
+ LeConnectionParameters::GetMinConnIntervalAggressive());
+ ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_max_,
+ LeConnectionParameters::GetMaxConnIntervalAggressive());
+}
+
+TEST_F(LeImplTest, aggressive_connection_mode_selected_when_few_le_connections_exist) {
+ if (LeConnectionParameters::GetAggressiveConnThreshold() == 0) {
+ GTEST_SKIP() << "Skipping test because the threshold is zero";
+ }
+
+ com::android::bluetooth::flags::provider_->initial_conn_params_p1(true);
+ set_random_device_address_policy();
+ controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
+
+ std::vector<std::unique_ptr<LeAclConnection>> connections;
+ for (uint32_t i = 0; i < LeConnectionParameters::GetAggressiveConnThreshold() - 1; i++) {
+ std::stringstream addr_string_stream;
+ addr_string_stream << "A0:05:04:03:02:" << std::hex << std::setw(2) << std::setfill('0') << i;
+
+ connections.push_back(create_enhanced_connection(addr_string_stream.str(), i /* handle */));
+ }
+
+ LeExtendedCreateConnectionView view = get_view_from_creating_connection("FF:EE:DD:CC:BB:AA");
+
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_min_,
+ LeConnectionParameters::GetMinConnIntervalAggressive());
+ ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_max_,
+ LeConnectionParameters::GetMaxConnIntervalAggressive());
+}
+
+TEST_F(LeImplTest, relaxed_connection_mode_selected_when_enough_le_connections_exist) {
+ com::android::bluetooth::flags::provider_->initial_conn_params_p1(true);
+ set_random_device_address_policy();
+ controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
+
+ std::vector<std::unique_ptr<LeAclConnection>> connections;
+ for (uint32_t i = 0; i < LeConnectionParameters::GetAggressiveConnThreshold(); i++) {
+ std::stringstream addr_string_stream;
+ addr_string_stream << "A0:05:04:03:02:" << std::hex << std::setw(2) << std::setfill('0') << i;
+
+ connections.push_back(create_enhanced_connection(addr_string_stream.str(), i /* handle */));
+ }
+
+ LeExtendedCreateConnectionView view = get_view_from_creating_connection("FF:EE:DD:CC:BB:AA");
+
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_min_,
+ LeConnectionParameters::GetMinConnIntervalRelaxed());
+ ASSERT_EQ(view.GetPhyScanParameters()[0].conn_interval_max_,
+ LeConnectionParameters::GetMaxConnIntervalRelaxed());
+}
+
// b/260917913
TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyNotSet) {
std::promise<void> promise;
diff --git a/system/gd/hci/address.h b/system/gd/hci/address.h
index b7e2bdeade..10a817cc1c 100644
--- a/system/gd/hci/address.h
+++ b/system/gd/hci/address.h
@@ -25,7 +25,6 @@
#include <ostream>
#include <string>
-#include "common/interfaces/ILoggable.h"
#include "os/logging/log_adapter.h"
#include "packet/custom_field_fixed_size_interface.h"
#include "storage/serializable.h"
@@ -34,8 +33,7 @@ namespace bluetooth {
namespace hci {
class Address final : public packet::CustomFieldFixedSizeInterface<Address>,
- public storage::Serializable<Address>,
- public bluetooth::common::IRedactableLoggable {
+ public storage::Serializable<Address> {
public:
static constexpr size_t kLength = 6;
@@ -56,8 +54,8 @@ public:
// storage::Serializable methods
std::string ToString() const override;
std::string ToColonSepHexString() const;
- std::string ToStringForLogging() const override;
- std::string ToRedactedStringForLogging() const override;
+ std::string ToStringForLogging() const;
+ std::string ToRedactedStringForLogging() const;
static std::optional<Address> FromString(const std::string& from);
std::string ToLegacyConfigString() const override;
@@ -89,13 +87,6 @@ private:
std::string _ToMaskedColonSepHexString(int bytes_to_mask) const;
};
-// TODO: to fine-tune this.
-// we need an interface between the logger and ILoggable
-inline std::ostream& operator<<(std::ostream& os, const Address& a) {
- os << a.ToString();
- return os;
-}
-
} // namespace hci
} // namespace bluetooth
diff --git a/system/gd/hci/address_with_type.h b/system/gd/hci/address_with_type.h
index c196989838..350b88df75 100644
--- a/system/gd/hci/address_with_type.h
+++ b/system/gd/hci/address_with_type.h
@@ -22,7 +22,6 @@
#include <string>
#include <utility>
-#include "common/interfaces/ILoggable.h"
#include "crypto_toolbox/crypto_toolbox.h"
#include "hci/address.h"
#include "hci/hci_packets.h"
@@ -32,7 +31,7 @@
namespace bluetooth {
namespace hci {
-class AddressWithType final : public bluetooth::common::IRedactableLoggable {
+class AddressWithType final {
public:
AddressWithType(Address address, AddressType address_type)
: address_(std::move(address)), address_type_(address_type) {}
@@ -109,16 +108,14 @@ public:
}
std::string ToString() const {
- std::stringstream ss;
- ss << address_ << "[" << AddressTypeText(address_type_) << "]";
- return ss.str();
+ return address_.ToString() + "[" + AddressTypeText(address_type_) + "]";
}
- std::string ToStringForLogging() const override {
+ std::string ToStringForLogging() const {
return address_.ToStringForLogging() + "[" + AddressTypeText(address_type_) + "]";
}
- std::string ToRedactedStringForLogging() const override {
+ std::string ToRedactedStringForLogging() const {
return address_.ToRedactedStringForLogging() + "[" + AddressTypeText(address_type_) + "]";
}
@@ -127,11 +124,6 @@ private:
AddressType address_type_;
};
-inline std::ostream& operator<<(std::ostream& os, const AddressWithType& a) {
- os << a.ToString();
- return os;
-}
-
} // namespace hci
} // namespace bluetooth
diff --git a/system/gd/hci/address_with_type_test.cc b/system/gd/hci/address_with_type_test.cc
index 3e0f34e4f9..c3b8bb0db9 100644
--- a/system/gd/hci/address_with_type_test.cc
+++ b/system/gd/hci/address_with_type_test.cc
@@ -294,14 +294,5 @@ TEST(AddressWithTypeTest, ToPeerAddressType) {
}
}
-TEST(AddressWithTypeTest, StringStream) {
- AddressWithType address_with_type = AddressWithType(Address{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}},
- AddressType::PUBLIC_DEVICE_ADDRESS);
-
- std::stringstream oss;
- oss << address_with_type;
- ASSERT_STREQ("66:55:44:33:22:11[PUBLIC_DEVICE_ADDRESS(0x00)]", oss.str().c_str());
-}
-
} // namespace hci
} // namespace bluetooth
diff --git a/system/gd/hci/class_of_device.h b/system/gd/hci/class_of_device.h
index d3a57fcc33..d4d53eb1d7 100644
--- a/system/gd/hci/class_of_device.h
+++ b/system/gd/hci/class_of_device.h
@@ -43,7 +43,7 @@ public:
inline const uint8_t* data() const override { return cod.data(); }
// storage::Serializable methods
- std::string ToString() const;
+ std::string ToString() const override;
static std::optional<ClassOfDevice> FromString(const std::string& str);
std::string ToLegacyConfigString() const override;
static std::optional<ClassOfDevice> FromLegacyConfigString(const std::string& str);
diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc
index 18180a547c..eaba7da848 100644
--- a/system/gd/hci/controller.cc
+++ b/system/gd/hci/controller.cc
@@ -25,7 +25,6 @@
#include <string>
#include <utility>
-#include "dumpsys_data_generated.h"
#include "hci/controller_interface.h"
#include "hci/event_checkers.h"
#include "hci/hci_layer.h"
@@ -44,8 +43,11 @@ constexpr int kMinEncryptionKeySizeDefault = kMinEncryptionKeySize;
constexpr int kMaxEncryptionKeySize = 16;
constexpr bool kDefaultVendorCapabilitiesEnabled = true;
+constexpr bool kDefaultRpaOffload = false;
+
static const std::string kPropertyVendorCapabilitiesEnabled =
"bluetooth.core.le.vendor_capabilities.enabled";
+static const std::string kPropertyRpaOffload = "bluetooth.core.le.rpa_offload";
using os::Handler;
@@ -1544,6 +1546,15 @@ uint64_t Controller::MaskLeEventMask(HciVersion version, uint64_t mask) {
}
}
+bool Controller::IsRpaGenerationSupported(void) const {
+ static const bool rpa_supported =
+ com::android::bluetooth::flags::rpa_offload_to_bt_controller() &&
+ os::GetSystemPropertyBool(kPropertyRpaOffload, kDefaultRpaOffload) &&
+ IsSupported(OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2);
+
+ return rpa_supported;
+}
+
const ModuleFactory Controller::Factory = ModuleFactory([]() { return new Controller(); });
void Controller::ListDependencies(ModuleList* list) const {
diff --git a/system/gd/hci/controller.h b/system/gd/hci/controller.h
index dcf0b10e42..70609950da 100644
--- a/system/gd/hci/controller.h
+++ b/system/gd/hci/controller.h
@@ -217,6 +217,8 @@ public:
static uint64_t MaskLeEventMask(HciVersion version, uint64_t mask);
+ virtual bool IsRpaGenerationSupported(void) const override;
+
protected:
void ListDependencies(ModuleList* list) const override;
diff --git a/system/gd/hci/controller_interface.h b/system/gd/hci/controller_interface.h
index 3dd3cd03d3..a9ebecd32a 100644
--- a/system/gd/hci/controller_interface.h
+++ b/system/gd/hci/controller_interface.h
@@ -215,6 +215,8 @@ public:
virtual VendorCapabilities GetVendorCapabilities() const = 0;
virtual bool IsSupported(OpCode op_code) const = 0;
+
+ virtual bool IsRpaGenerationSupported(void) const = 0;
};
} // namespace hci
diff --git a/system/gd/hci/controller_interface_mock.h b/system/gd/hci/controller_interface_mock.h
index 6c8a2811d9..36bc50a423 100644
--- a/system/gd/hci/controller_interface_mock.h
+++ b/system/gd/hci/controller_interface_mock.h
@@ -149,6 +149,7 @@ public:
MOCK_METHOD(std::vector<uint8_t>, GetLocalSupportedBrEdrCodecIds, (), (const));
MOCK_METHOD(VendorCapabilities, GetVendorCapabilities, (), (const));
MOCK_METHOD(bool, IsSupported, (OpCode op_code), (const));
+ MOCK_METHOD(bool, IsRpaGenerationSupported, (), (const));
MOCK_METHOD(uint32_t, GetDabSupportedCodecs, (), (const));
MOCK_METHOD((const std::array<DynamicAudioBufferCodecCapability, 32>&), GetDabCodecCapabilities,
diff --git a/system/gd/hci/controller_mock.h b/system/gd/hci/controller_mock.h
index 1c05ad983b..fd3a7058d1 100644
--- a/system/gd/hci/controller_mock.h
+++ b/system/gd/hci/controller_mock.h
@@ -149,6 +149,7 @@ public:
MOCK_METHOD(std::vector<uint8_t>, GetLocalSupportedBrEdrCodecIds, (), (const));
MOCK_METHOD(VendorCapabilities, GetVendorCapabilities, (), (const));
MOCK_METHOD(bool, IsSupported, (OpCode op_code), (const));
+ MOCK_METHOD(bool, IsRpaGenerationSupported, (), (const));
MOCK_METHOD(uint32_t, GetDabSupportedCodecs, (), (const));
MOCK_METHOD((const std::array<DynamicAudioBufferCodecCapability, 32>&), GetDabCodecCapabilities,
diff --git a/system/gd/hci/controller_test.cc b/system/gd/hci/controller_test.cc
index 04b1380fa4..05dcaf9d7e 100644
--- a/system/gd/hci/controller_test.cc
+++ b/system/gd/hci/controller_test.cc
@@ -29,7 +29,6 @@
#include "common/bind.h"
#include "hci/address.h"
#include "hci/hci_layer_fake.h"
-#include "module_dumper.h"
#include "os/thread.h"
#include "packet/raw_builder.h"
diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc
index 9bf07a6c47..04c3955204 100644
--- a/system/gd/hci/distance_measurement_manager.cc
+++ b/system/gd/hci/distance_measurement_manager.cc
@@ -63,17 +63,20 @@ static constexpr uint16_t kMinProcedureInterval = 0x01;
static constexpr uint16_t kMaxProcedureInterval = 0xFF;
static constexpr uint16_t kMaxProcedureCount = 0x01;
static constexpr uint32_t kMinSubeventLen = 0x0004E2; // 1250us
-static constexpr uint32_t kMaxSubeventLen = 0x3d0900; // 4s
+static constexpr uint32_t kMaxSubeventLen = 0x1E8480; // 2s
static constexpr uint8_t kTxPwrDelta = 0x00;
static constexpr uint8_t kProcedureDataBufferSize = 0x10; // Buffer size of Procedure data
-static constexpr uint16_t kMtuForRasData = 507; // 512 - 5
static constexpr uint16_t kRangingCounterMask = 0x0FFF;
static constexpr uint8_t kInvalidConfigId = 0xFF;
static constexpr uint8_t kMinConfigId = 0;
static constexpr uint8_t kMaxConfigId = 3;
static constexpr uint16_t kDefaultIntervalMs = 1000; // 1s
static constexpr uint8_t kMaxRetryCounterForCreateConfig = 0x03;
+static constexpr uint8_t kMaxRetryCounterForCsEnable = 0x03;
static constexpr uint16_t kInvalidConnInterval = 0; // valid value is from 0x0006 to 0x0C80
+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;
struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
struct CsProcedureData {
@@ -182,6 +185,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
bool ras_connected = false;
bool setup_complete = false;
uint8_t retry_counter_for_create_config = 0;
+ uint8_t retry_counter_for_cs_enable = 0;
uint16_t n_procedure_count = 0;
CsMainModeType main_mode_type = CsMainModeType::MODE_2;
CsSubModeType sub_mode_type = CsSubModeType::UNUSED;
@@ -204,6 +208,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
RangingHeader ranging_header_;
PacketViewForRecombination segment_data_;
uint16_t conn_interval_ = kInvalidConnInterval;
+ uint8_t procedure_sequence_after_enable = -1;
};
bool get_free_config_id(uint16_t connection_handle, uint8_t& config_id) {
@@ -409,7 +414,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
void start_distance_measurement_with_cs(const Address& cs_remote_address,
uint16_t connection_handle) {
log::info("connection_handle: {}, address: {}", connection_handle, cs_remote_address);
- if (!com::android::bluetooth::flags::channel_sounding_in_stack() && !is_local_cs_ready_) {
+ if (!com::android::bluetooth::flags::channel_sounding_in_stack() || !is_local_cs_ready_) {
log::error("Channel Sounding is not enabled");
distance_measurement_callbacks_->OnDistanceMeasurementStopped(
cs_remote_address, REASON_INTERNAL_ERROR, METHOD_CS);
@@ -504,7 +509,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
void handle_conn_interval_updated(const Address& address, uint16_t connection_handle,
uint16_t conn_interval) {
- if (com::android::bluetooth::flags::channel_sounding_25q2_apis()) {
+ if (!com::android::bluetooth::flags::channel_sounding_25q2_apis()) {
log::debug("connection interval is not required.");
return;
}
@@ -532,6 +537,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
}
distance_measurement_callbacks_->OnDistanceMeasurementStopped(
address, REASON_NO_LE_CONNECTION, METHOD_CS);
+ gatt_mtus_.erase(it->first);
it = cs_requester_trackers_.erase(it); // erase and get the next iterator
} else {
++it;
@@ -578,6 +584,20 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
it->second.local_hci_role = local_hci_role;
}
+ void handle_mtu_changed(uint16_t connection_handle, uint16_t mtu) {
+ log::info("gatt mtu is changed as {}", mtu);
+ gatt_mtus_[connection_handle] = mtu;
+ }
+
+ uint16_t get_ras_raw_payload_size(uint16_t connection_handle) {
+ auto it = gatt_mtus_.find(connection_handle);
+ uint16_t mtu = kDefaultRasMtu;
+ if (it != gatt_mtus_.end()) {
+ mtu = gatt_mtus_[connection_handle];
+ }
+ return mtu - kAttHeaderSize - kRasSegmentHeaderSize;
+ }
+
void handle_ras_server_disconnected(const Address& identity_address, uint16_t connection_handle) {
auto it = cs_responder_trackers_.find(connection_handle);
if (it == cs_responder_trackers_.end()) {
@@ -590,6 +610,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
return;
}
cs_responder_trackers_.erase(connection_handle);
+ gatt_mtus_.erase(connection_handle);
}
void handle_vendor_specific_reply_complete(const Address address, uint16_t connection_handle,
@@ -673,11 +694,25 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
handler_->BindOnceOn(this, &impl::on_cs_setup_command_status_cb, connection_handle));
}
- void send_le_cs_security_enable(uint16_t connection_handle) {
- if (cs_requester_trackers_.find(connection_handle) == cs_requester_trackers_.end()) {
- log::warn("no cs tracker found for {}", connection_handle);
+ void send_le_cs_security_enable(uint16_t connection_handle, bool local_start) {
+ if (local_start) {
+ auto req_it = cs_requester_trackers_.find(connection_handle);
+ if (req_it != cs_requester_trackers_.end() &&
+ req_it->second.state == CsTrackerState::WAIT_FOR_CONFIG_COMPLETE) {
+ req_it->second.state = CsTrackerState::WAIT_FOR_SECURITY_ENABLED;
+ } else {
+ log::error("no requester tracker. something wrong.");
+ }
+ } else {
+ auto res_it = cs_responder_trackers_.find(connection_handle);
+ if (res_it != cs_responder_trackers_.end() &&
+ res_it->second.state == CsTrackerState::WAIT_FOR_CONFIG_COMPLETE) {
+ res_it->second.state = CsTrackerState::WAIT_FOR_SECURITY_ENABLED;
+ } else {
+ log::error("no responder tracker. something wrong.");
+ }
}
- cs_requester_trackers_[connection_handle].state = CsTrackerState::WAIT_FOR_SECURITY_ENABLED;
+
hci_layer_->EnqueueCommand(
LeCsSecurityEnableBuilder::Create(connection_handle),
handler_->BindOnceOn(this, &impl::on_cs_setup_command_status_cb, connection_handle));
@@ -710,7 +745,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
connection_handle, config_id, CsCreateContext::BOTH_LOCAL_AND_REMOTE_CONTROLLER,
CsMainModeType::MODE_2, CsSubModeType::UNUSED, kMinMainModeSteps,
kMaxMainModeSteps, kMainModeRepetition, kMode0Steps, CsRole::INITIATOR,
- CsConfigRttType::RTT_AA_COARSE, CsSyncPhy::LE_1M_PHY, channel_map,
+ CsConfigRttType::RTT_AA_ONLY, CsSyncPhy::LE_1M_PHY, channel_map,
kChannelMapRepetition, CsChannelSelectionType::TYPE_3B, CsCh3cShape::HAT_SHAPE,
kCh3cJump),
handler_->BindOnceOn(this, &impl::on_cs_setup_command_status_cb, connection_handle));
@@ -809,8 +844,20 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
if (cs_requester_trackers_.find(connection_handle) != cs_requester_trackers_.end()) {
reset_tracker_on_stopped(cs_requester_trackers_[connection_handle]);
}
- } else {
- on_cs_setup_command_status_cb(connection_handle, status_view);
+ } else if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ if (cs_requester_trackers_.count(connection_handle) == 0) {
+ log::error("Error code {} for connection_handle {}. No request tracker found.",
+ ErrorCodeText(status), connection_handle);
+ handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
+ return;
+ }
+ log::error("Error code {} for connection_handle {}. Retry counter {}", ErrorCodeText(status),
+ connection_handle,
+ cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable);
+ if (cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable++ >=
+ kMaxRetryCounterForCsEnable) {
+ handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
+ }
}
}
@@ -818,7 +865,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
ErrorCode status = status_view.GetStatus();
OpCode op_code = status_view.GetCommandOpCode();
if (status != ErrorCode::SUCCESS) {
- log::error("Error code {}, opcode {} for connection-{}", ErrorCodeText(status),
+ log::error("Error code {}, opcode {} for connection_handle {}", ErrorCodeText(status),
OpCodeText(op_code), connection_handle);
handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
}
@@ -911,7 +958,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
return;
}
auto req_it = cs_requester_trackers_.find(connection_handle);
- if (req_it != cs_requester_trackers_.end() && req_it->second.measurement_ongoing) {
+ 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(),
req_it->second.used_config_id,
req_it->second.remote_num_antennas_supported_);
@@ -965,6 +1013,10 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
log::warn("Can't find cs tracker for connection_handle {}", connection_handle);
return;
}
+ if (!live_tracker->local_start) {
+ // reset the responder state, as no other event to set the state.
+ live_tracker->state = CsTrackerState::WAIT_FOR_CONFIG_COMPLETE;
+ }
live_tracker->used_config_id = config_id;
log::info("Get {}", event_view.ToString());
@@ -979,10 +1031,9 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
}
if (live_tracker->local_hci_role == hci::Role::CENTRAL) {
// send the cmd from the BLE central only.
- send_le_cs_security_enable(connection_handle);
- }
- // TODO: else set a timeout alarm to make sure the remote would trigger the cmd.
- if (!live_tracker->local_start) {
+ 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;
}
}
@@ -1091,8 +1142,20 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
log::debug("on cs procedure enabled complete");
if (event_view.GetStatus() != ErrorCode::SUCCESS) {
std::string error_code = ErrorCodeText(event_view.GetStatus());
- log::warn("Received LeCsProcedureEnableCompleteView with error code {}", error_code);
- handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
+ if (cs_requester_trackers_.count(connection_handle) == 0) {
+ log::warn(
+ "Received LeCsProcedureEnableCompleteView with error code {}, No request tracker "
+ "found",
+ error_code);
+ handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
+ return;
+ }
+ log::warn("Received LeCsProcedureEnableCompleteView with error code {}. Retry counter {}",
+ error_code, cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable);
+ if (cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable++ >=
+ kMaxRetryCounterForCsEnable) {
+ handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
+ }
return;
}
uint8_t config_id = event_view.GetConfigId();
@@ -1123,6 +1186,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
live_tracker->state = CsTrackerState::STARTED;
live_tracker->selected_tx_power = event_view.GetSelectedTxPower();
live_tracker->n_procedure_count = event_view.GetProcedureCount();
+ live_tracker->retry_counter_for_cs_enable = 0;
if (live_tracker->local_start && live_tracker->waiting_for_start_callback) {
live_tracker->waiting_for_start_callback = false;
@@ -1130,6 +1194,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
METHOD_CS);
}
if (live_tracker->local_start && is_hal_v2()) {
+ // reset the procedure sequence
+ live_tracker->procedure_sequence_after_enable = -1;
ranging_hal_->UpdateProcedureEnableConfig(connection_handle, event_view);
}
} else if (event_view.GetState() == Enable::DISABLED) {
@@ -1171,6 +1237,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
CsTracker* live_tracker = nullptr;
CsProcedureData* procedure_data = nullptr;
uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED);
+ // TODO(b/384928509): Prevent sending CS enable if procedures are not yet complete.
+ valid_requester_states |= static_cast<uint8_t>(CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED);
uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::STARTED);
if (event.GetSubeventCode() == SubeventCode::LE_CS_SUBEVENT_RESULT) {
auto cs_event_result = LeCsSubeventResultView::Create(event);
@@ -1292,9 +1360,9 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
static_cast<bluetooth::ras::SubeventAbortReason>(subevent_abort_reason);
}
parse_cs_result_data(result_data_structures, *procedure_data, live_tracker->role);
- check_cs_procedure_complete(live_tracker, procedure_data, connection_handle);
if (live_tracker->local_start) {
+ check_cs_procedure_complete(live_tracker, procedure_data, connection_handle);
// Skip to send remote
return;
}
@@ -1311,7 +1379,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
append_vector(procedure_data->ras_raw_data_, subevent_raw);
// erase buffer
procedure_data->ras_subevent_data_.clear();
- send_on_demand_data(live_tracker->address, procedure_data);
+ send_on_demand_data(live_tracker->address, procedure_data,
+ get_ras_raw_payload_size(connection_handle));
// remove procedure data sent previously
if (procedure_done_status == CsProcedureDoneStatus::ALL_RESULTS_COMPLETE) {
delete_consumed_procedure_data(live_tracker, live_tracker->procedure_counter);
@@ -1319,20 +1388,21 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
}
}
- void send_on_demand_data(Address address, CsProcedureData* procedure_data) {
+ void send_on_demand_data(Address address, CsProcedureData* procedure_data,
+ uint16_t raw_payload_size) {
// Check is last segment or not.
uint16_t unsent_data_size =
procedure_data->ras_raw_data_.size() - procedure_data->ras_raw_data_index_;
if (procedure_data->local_status != CsProcedureDoneStatus::PARTIAL_RESULTS &&
- unsent_data_size <= kMtuForRasData) {
+ unsent_data_size <= raw_payload_size) {
procedure_data->segmentation_header_.last_segment_ = 1;
- } else if (unsent_data_size < kMtuForRasData) {
+ } else if (unsent_data_size < raw_payload_size) {
log::verbose("waiting for more data, current unsent data size {}", unsent_data_size);
return;
}
// Create raw data for segment_data;
- uint16_t copy_size = unsent_data_size < kMtuForRasData ? unsent_data_size : kMtuForRasData;
+ uint16_t copy_size = unsent_data_size < raw_payload_size ? unsent_data_size : raw_payload_size;
auto copy_start = procedure_data->ras_raw_data_.begin() + procedure_data->ras_raw_data_index_;
auto copy_end = copy_start + copy_size;
std::vector<uint8_t> subevent_data(copy_start, copy_end);
@@ -1353,8 +1423,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
if (procedure_data->segmentation_header_.last_segment_) {
// last segment sent, clear buffer
procedure_data->ras_raw_data_.clear();
- } else if (unsent_data_size > kMtuForRasData) {
- send_on_demand_data(address, procedure_data);
+ } else if (unsent_data_size > raw_payload_size) {
+ send_on_demand_data(address, procedure_data, raw_payload_size);
}
}
@@ -1896,40 +1966,59 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
return procedure_data;
}
+ void try_send_data_to_hal(uint16_t connection_handle, const CsTracker* live_tracker,
+ const CsProcedureData* procedure_data) const {
+ if (!ranging_hal_->IsBound()) {
+ return;
+ }
+ bool should_send_to_hal = false;
+ if (ranging_hal_->IsAbortedProcedureRequired(connection_handle)) {
+ should_send_to_hal = procedure_data->local_status != CsProcedureDoneStatus::PARTIAL_RESULTS &&
+ procedure_data->remote_status != CsProcedureDoneStatus::PARTIAL_RESULTS;
+ } else {
+ should_send_to_hal =
+ procedure_data->local_status == CsProcedureDoneStatus::ALL_RESULTS_COMPLETE &&
+ procedure_data->remote_status == CsProcedureDoneStatus::ALL_RESULTS_COMPLETE &&
+ procedure_data->contains_complete_subevent_;
+ }
+ if (should_send_to_hal) {
+ log::debug("Procedure complete counter:{} data size:{}", (uint16_t)procedure_data->counter,
+ procedure_data->step_channel.size());
+ if (is_hal_v2()) {
+ ranging_hal_->WriteProcedureData(connection_handle, live_tracker->role,
+ procedure_data->procedure_data_v2_,
+ procedure_data->counter);
+ } else {
+ // Use algorithm in the HAL
+ bluetooth::hal::ChannelSoundingRawData raw_data;
+ raw_data.num_antenna_paths_ = procedure_data->num_antenna_paths;
+ raw_data.step_channel_ = procedure_data->step_channel;
+ raw_data.tone_pct_initiator_ = procedure_data->tone_pct_initiator;
+ raw_data.tone_quality_indicator_initiator_ =
+ procedure_data->tone_quality_indicator_initiator;
+ raw_data.tone_pct_reflector_ = procedure_data->tone_pct_reflector;
+ raw_data.tone_quality_indicator_reflector_ =
+ procedure_data->tone_quality_indicator_reflector;
+ raw_data.toa_tod_initiators_ = procedure_data->toa_tod_initiators;
+ raw_data.tod_toa_reflectors_ = procedure_data->tod_toa_reflectors;
+ raw_data.packet_quality_initiator = procedure_data->packet_quality_initiator;
+ raw_data.packet_quality_reflector = procedure_data->packet_quality_reflector;
+ ranging_hal_->WriteRawData(connection_handle, raw_data);
+ }
+ }
+ }
+
void check_cs_procedure_complete(CsTracker* live_tracker, CsProcedureData* procedure_data,
uint16_t connection_handle) const {
- if (live_tracker->local_start &&
- procedure_data->local_status == CsProcedureDoneStatus::ALL_RESULTS_COMPLETE &&
- procedure_data->remote_status == CsProcedureDoneStatus::ALL_RESULTS_COMPLETE &&
- procedure_data->contains_complete_subevent_) {
- log::debug("Procedure complete counter:{} data size:{}, main_mode_type:{}, sub_mode_type:{}",
- (uint16_t)procedure_data->counter, (uint16_t)procedure_data->step_channel.size(),
- (uint16_t)live_tracker->main_mode_type, (uint16_t)live_tracker->sub_mode_type);
-
- if (ranging_hal_->IsBound()) {
- if (is_hal_v2()) {
- ranging_hal_->WriteProcedureData(connection_handle, live_tracker->role,
- procedure_data->procedure_data_v2_,
- procedure_data->counter);
- } else {
- // Use algorithm in the HAL
- bluetooth::hal::ChannelSoundingRawData raw_data;
- raw_data.num_antenna_paths_ = procedure_data->num_antenna_paths;
- raw_data.step_channel_ = procedure_data->step_channel;
- raw_data.tone_pct_initiator_ = procedure_data->tone_pct_initiator;
- raw_data.tone_quality_indicator_initiator_ =
- procedure_data->tone_quality_indicator_initiator;
- raw_data.tone_pct_reflector_ = procedure_data->tone_pct_reflector;
- raw_data.tone_quality_indicator_reflector_ =
- procedure_data->tone_quality_indicator_reflector;
- raw_data.toa_tod_initiators_ = procedure_data->toa_tod_initiators;
- raw_data.tod_toa_reflectors_ = procedure_data->tod_toa_reflectors;
- raw_data.packet_quality_initiator = procedure_data->packet_quality_initiator;
- raw_data.packet_quality_reflector = procedure_data->packet_quality_reflector;
- ranging_hal_->WriteRawData(connection_handle, raw_data);
- }
- }
+ if (is_hal_v2() && procedure_data->local_status != CsProcedureDoneStatus::PARTIAL_RESULTS &&
+ procedure_data->remote_status != CsProcedureDoneStatus::PARTIAL_RESULTS) {
+ live_tracker->procedure_sequence_after_enable++;
+ log::debug("procedure sequence after enabled is {}",
+ live_tracker->procedure_sequence_after_enable);
+ procedure_data->procedure_data_v2_.procedure_sequence_ =
+ live_tracker->procedure_sequence_after_enable;
}
+ try_send_data_to_hal(connection_handle, live_tracker, procedure_data);
// If the procedure is completed or aborted, delete all previous data
if (procedure_data->local_status != CsProcedureDoneStatus::PARTIAL_RESULTS &&
@@ -2413,6 +2502,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
std::unordered_map<Address, RSSITracker> rssi_trackers;
std::unordered_map<uint16_t, CsTracker> cs_requester_trackers_;
std::unordered_map<uint16_t, CsTracker> cs_responder_trackers_;
+ std::unordered_map<uint16_t, uint16_t> gatt_mtus_;
DistanceMeasurementCallbacks* distance_measurement_callbacks_;
CsOptionalSubfeaturesSupported cs_subfeature_supported_;
uint8_t num_antennas_supported_ = 0x01;
@@ -2506,6 +2596,10 @@ void DistanceMeasurementManager::HandleRasServerConnected(const Address& identit
local_hci_role);
}
+void DistanceMeasurementManager::HandleMtuChanged(uint16_t connection_handle, uint16_t mtu) {
+ CallOn(pimpl_.get(), &impl::handle_mtu_changed, connection_handle, mtu);
+}
+
void DistanceMeasurementManager::HandleRasServerDisconnected(
const bluetooth::hci::Address& identity_address, uint16_t connection_handle) {
CallOn(pimpl_.get(), &impl::handle_ras_server_disconnected, identity_address, connection_handle);
diff --git a/system/gd/hci/distance_measurement_manager.h b/system/gd/hci/distance_measurement_manager.h
index 4f8f19a9ff..da26425c49 100644
--- a/system/gd/hci/distance_measurement_manager.h
+++ b/system/gd/hci/distance_measurement_manager.h
@@ -94,6 +94,7 @@ public:
const std::vector<hal::VendorSpecificCharacteristic>& vendor_specific_reply);
void HandleRasServerConnected(const Address& identity_address, uint16_t connection_handle,
hci::Role local_hci_role);
+ void HandleMtuChanged(uint16_t connection_handle, uint16_t mtu);
void HandleRasServerDisconnected(const Address& identity_address, uint16_t connection_handle);
void HandleVendorSpecificReplyComplete(const Address& address, uint16_t connection_handle,
bool success);
diff --git a/system/gd/hci/facade/acl_manager_facade.cc b/system/gd/hci/facade/acl_manager_facade.cc
deleted file mode 100644
index c885f9d683..0000000000
--- a/system/gd/hci/facade/acl_manager_facade.cc
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Copyright 2019 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 "hci/facade/acl_manager_facade.h"
-
-#include <bluetooth/log.h>
-
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-
-#include "blueberry/facade/hci/acl_manager_facade.grpc.pb.h"
-#include "blueberry/facade/hci/acl_manager_facade.pb.h"
-#include "common/bind.h"
-#include "grpc/grpc_event_queue.h"
-#include "hci/acl_manager.h"
-#include "hci/address.h"
-#include "hci/class_of_device.h"
-#include "hci/hci_packets.h"
-#include "packet/raw_builder.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-using ::bluetooth::packet::RawBuilder;
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using acl_manager::ClassicAclConnection;
-using acl_manager::ConnectionCallbacks;
-using acl_manager::ConnectionManagementCallbacks;
-
-using namespace blueberry::facade::hci;
-
-class AclManagerFacadeService : public AclManagerFacade::Service, public ConnectionCallbacks {
-public:
- AclManagerFacadeService(AclManager* acl_manager, ::bluetooth::os::Handler* facade_handler)
- : acl_manager_(acl_manager), facade_handler_(facade_handler) {
- acl_manager_->RegisterCallbacks(this, facade_handler_);
- }
-
- ~AclManagerFacadeService() {
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- for (auto& connection : acl_connections_) {
- connection.second.connection_->GetAclQueueEnd()->UnregisterDequeue();
- }
- }
-
- ::grpc::Status CreateConnection(::grpc::ServerContext* context, const ConnectionMsg* request,
- ::grpc::ServerWriter<ConnectionEvent>* writer) override {
- log::info("peer={}", request->address());
- Address peer;
- log::assert_that(Address::FromString(request->address(), peer),
- "assert failed: Address::FromString(request->address(), peer)");
- acl_manager_->CreateConnection(peer);
- if (per_connection_events_.size() > current_connection_request_) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Only one outstanding request is supported");
- }
- per_connection_events_.emplace_back(
- std::make_unique<::bluetooth::grpc::GrpcEventQueue<ConnectionEvent>>(
- std::string("connection attempt ") +
- std::to_string(current_connection_request_)));
- return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
- }
-
- ::grpc::Status Disconnect(::grpc::ServerContext* /* context */, const HandleMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("handle={}", request->handle());
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- log::error("Invalid handle");
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- } else {
- connection->second.connection_->Disconnect(
- DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
- return ::grpc::Status::OK;
- }
- }
-
- ::grpc::Status AuthenticationRequested(::grpc::ServerContext* /* context */,
- const HandleMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("handle={}", request->handle());
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- log::error("Invalid handle");
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- } else {
- connection->second.connection_->AuthenticationRequested();
- return ::grpc::Status::OK;
- }
- }
-
-#define GET_CONNECTION(view) \
- std::map<uint16_t, Connection>::iterator connection; \
- do { \
- if (!view.IsValid()) { \
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle"); \
- } \
- std::unique_lock<std::mutex> lock(acl_connections_mutex_); \
- connection = acl_connections_.find(view.GetConnectionHandle()); \
- if (connection == acl_connections_.end()) { \
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle"); \
- } \
- } while (0)
-
- ::grpc::Status ConnectionCommand(::grpc::ServerContext* /* context */,
- const ConnectionCommandMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("size={}", request->packet().size());
- auto command_view = ConnectionManagementCommandView::Create(AclCommandView::Create(
- CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>(
- request->packet().begin(), request->packet().end())))));
- if (!command_view.IsValid()) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid command packet");
- }
- log::info("opcode={}", OpCodeText(command_view.GetOpCode()));
- switch (command_view.GetOpCode()) {
- case OpCode::AUTHENTICATION_REQUESTED: {
- GET_CONNECTION(AuthenticationRequestedView::Create(command_view));
- connection->second.connection_->AuthenticationRequested();
- return ::grpc::Status::OK;
- }
- case OpCode::DISCONNECT: {
- auto view = DisconnectView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->Disconnect(view.GetReason());
- return ::grpc::Status::OK;
- }
- case OpCode::CHANGE_CONNECTION_PACKET_TYPE: {
- auto view = ChangeConnectionPacketTypeView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->ChangeConnectionPacketType(view.GetPacketType());
- return ::grpc::Status::OK;
- }
- case OpCode::SET_CONNECTION_ENCRYPTION: {
- auto view = SetConnectionEncryptionView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->SetConnectionEncryption(view.GetEncryptionEnable());
- return ::grpc::Status::OK;
- }
- case OpCode::CHANGE_CONNECTION_LINK_KEY: {
- GET_CONNECTION(ChangeConnectionLinkKeyView::Create(command_view));
- connection->second.connection_->ChangeConnectionLinkKey();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_CLOCK_OFFSET: {
- GET_CONNECTION(ReadClockOffsetView::Create(command_view));
- connection->second.connection_->ReadClockOffset();
- return ::grpc::Status::OK;
- }
- case OpCode::HOLD_MODE: {
- auto view = HoldModeView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->HoldMode(view.GetHoldModeMaxInterval(),
- view.GetHoldModeMinInterval());
- return ::grpc::Status::OK;
- }
- case OpCode::SNIFF_MODE: {
- auto view = SniffModeView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->SniffMode(view.GetSniffMaxInterval(),
- view.GetSniffMinInterval(),
- view.GetSniffAttempt(), view.GetSniffTimeout());
- return ::grpc::Status::OK;
- }
- case OpCode::EXIT_SNIFF_MODE: {
- GET_CONNECTION(ExitSniffModeView::Create(command_view));
- connection->second.connection_->ExitSniffMode();
- return ::grpc::Status::OK;
- }
- case OpCode::FLUSH: {
- GET_CONNECTION(FlushView::Create(command_view));
- connection->second.connection_->Flush();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT: {
- GET_CONNECTION(ReadAutomaticFlushTimeoutView::Create(command_view));
- connection->second.connection_->ReadAutomaticFlushTimeout();
- return ::grpc::Status::OK;
- }
- case OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT: {
- auto view = WriteAutomaticFlushTimeoutView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->WriteAutomaticFlushTimeout(view.GetFlushTimeout());
- return ::grpc::Status::OK;
- }
- case OpCode::READ_TRANSMIT_POWER_LEVEL: {
- auto view = ReadTransmitPowerLevelView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->ReadTransmitPowerLevel(view.GetTransmitPowerLevelType());
- return ::grpc::Status::OK;
- }
- case OpCode::READ_LINK_SUPERVISION_TIMEOUT: {
- GET_CONNECTION(ReadLinkSupervisionTimeoutView::Create(command_view));
- connection->second.connection_->ReadLinkSupervisionTimeout();
- return ::grpc::Status::OK;
- }
- case OpCode::WRITE_LINK_SUPERVISION_TIMEOUT: {
- auto view = WriteLinkSupervisionTimeoutView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->WriteLinkSupervisionTimeout(
- view.GetLinkSupervisionTimeout());
- return ::grpc::Status::OK;
- }
- case OpCode::READ_FAILED_CONTACT_COUNTER: {
- GET_CONNECTION(ReadFailedContactCounterView::Create(command_view));
- connection->second.connection_->ReadFailedContactCounter();
- return ::grpc::Status::OK;
- }
- case OpCode::RESET_FAILED_CONTACT_COUNTER: {
- GET_CONNECTION(ResetFailedContactCounterView::Create(command_view));
- connection->second.connection_->ResetFailedContactCounter();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_LINK_QUALITY: {
- GET_CONNECTION(ReadLinkQualityView::Create(command_view));
- connection->second.connection_->ReadLinkQuality();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_AFH_CHANNEL_MAP: {
- GET_CONNECTION(ReadAfhChannelMapView::Create(command_view));
- connection->second.connection_->ReadAfhChannelMap();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_RSSI: {
- GET_CONNECTION(ReadRssiView::Create(command_view));
- connection->second.connection_->ReadRssi();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_CLOCK: {
- auto view = ReadClockView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->ReadClock(view.GetWhichClock());
- return ::grpc::Status::OK;
- }
- case OpCode::READ_REMOTE_VERSION_INFORMATION: {
- GET_CONNECTION(ReadRemoteVersionInformationView::Create(command_view));
- connection->second.connection_->ReadRemoteVersionInformation();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_REMOTE_SUPPORTED_FEATURES: {
- GET_CONNECTION(ReadRemoteSupportedFeaturesView::Create(command_view));
- connection->second.connection_->ReadRemoteSupportedFeatures();
- return ::grpc::Status::OK;
- }
- case OpCode::READ_REMOTE_EXTENDED_FEATURES: {
- GET_CONNECTION(ReadRemoteExtendedFeaturesView::Create(command_view));
- uint8_t page_number = 0;
- connection->second.connection_->ReadRemoteExtendedFeatures(page_number);
- return ::grpc::Status::OK;
- }
- default:
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid command packet");
- }
- }
-#undef GET_CONNECTION
-
- ::grpc::Status FetchIncomingConnection(::grpc::ServerContext* context,
- const google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<ConnectionEvent>* writer) override {
- log::info("wait for one incoming connection");
- if (per_connection_events_.size() > current_connection_request_) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Only one outstanding connection is supported");
- }
- per_connection_events_.emplace_back(
- std::make_unique<::bluetooth::grpc::GrpcEventQueue<ConnectionEvent>>(
- std::string("incoming connection ") +
- std::to_string(current_connection_request_)));
- return per_connection_events_[current_connection_request_]->RunLoop(context, writer);
- }
-
- ::grpc::Status SendAclData(::grpc::ServerContext* /* context */, const AclData* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("handle={}, size={}", request->handle(), request->payload().size());
- std::promise<void> promise;
- auto future = promise.get_future();
- {
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- }
- // TODO: This is unsafe because connection may have gone
- connection->second.connection_->GetAclQueueEnd()->RegisterEnqueue(
- facade_handler_,
- common::Bind(&AclManagerFacadeService::enqueue_packet, common::Unretained(this),
- common::Unretained(request), common::Passed(std::move(promise))));
- auto status = future.wait_for(std::chrono::milliseconds(1000));
- if (status != std::future_status::ready) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Can't send packet");
- }
- }
- return ::grpc::Status::OK;
- }
-
- std::unique_ptr<BasePacketBuilder> enqueue_packet(const AclData* request,
- std::promise<void> promise) {
- auto connection = acl_connections_.find(request->handle());
- log::assert_that(connection != acl_connections_.end(), "handle {}", request->handle());
- connection->second.connection_->GetAclQueueEnd()->UnregisterEnqueue();
- std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>(
- std::vector<uint8_t>(request->payload().begin(), request->payload().end()));
- promise.set_value();
- return packet;
- }
-
- ::grpc::Status FetchAclData(::grpc::ServerContext* context, const HandleMsg* request,
- ::grpc::ServerWriter<AclData>* writer) override {
- log::info("handle={}", request->handle());
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- }
- return connection->second.pending_acl_data_.RunLoop(context, writer);
- }
-
- static inline uint16_t to_handle(uint32_t current_request) {
- return (current_request + 0x10) % 0xe00;
- }
-
- static inline std::string builder_to_string(std::unique_ptr<BasePacketBuilder> builder) {
- std::vector<uint8_t> bytes;
- BitInserter bit_inserter(bytes);
- builder->Serialize(bit_inserter);
- return std::string(bytes.begin(), bytes.end());
- }
-
- void on_incoming_acl(std::shared_ptr<ClassicAclConnection> connection, uint16_t handle) {
- log::info("handle={}, addr={}", connection->GetHandle(), connection->GetAddress());
- auto packet = connection->GetAclQueueEnd()->TryDequeue();
- auto connection_tracker = acl_connections_.find(handle);
- log::assert_that(connection_tracker != acl_connections_.end(), "handle {}", handle);
- AclData acl_data;
- acl_data.set_handle(handle);
- acl_data.set_payload(std::string(packet->begin(), packet->end()));
- log::info("length={}", acl_data.payload().size());
- connection_tracker->second.pending_acl_data_.OnIncomingEvent(acl_data);
- }
-
- void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
- log::info("handle={}, addr={}", connection->GetHandle(), connection->GetAddress());
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- std::shared_ptr<ClassicAclConnection> shared_connection = std::move(connection);
- uint16_t handle = to_handle(current_connection_request_);
- acl_connections_.erase(handle);
- acl_connections_.emplace(
- std::piecewise_construct, std::forward_as_tuple(handle),
- std::forward_as_tuple(handle, shared_connection,
- per_connection_events_[current_connection_request_]));
- shared_connection->GetAclQueueEnd()->RegisterDequeue(
- facade_handler_, common::Bind(&AclManagerFacadeService::on_incoming_acl,
- common::Unretained(this), shared_connection, handle));
- auto callbacks = acl_connections_.find(handle)->second.GetCallbacks();
- shared_connection->RegisterCallbacks(callbacks, facade_handler_);
- auto addr = shared_connection->GetAddress();
- std::unique_ptr<BasePacketBuilder> builder = ConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, handle, addr, LinkType::ACL, Enable::DISABLED);
- ConnectionEvent success;
- success.set_payload(builder_to_string(std::move(builder)));
- per_connection_events_[current_connection_request_]->OnIncomingEvent(success);
- current_connection_request_++;
- }
-
- void OnConnectRequest(Address /* address */, ClassOfDevice /* cod */) override {
- log::error("Remote connect request unimplemented");
- }
-
- void OnConnectFail(Address address, ErrorCode reason, bool /* locally_initiated */) override {
- log::info("addr={}, reason={}", address, ErrorCodeText(reason));
- std::unique_ptr<BasePacketBuilder> builder =
- ConnectionCompleteBuilder::Create(reason, 0, address, LinkType::ACL, Enable::DISABLED);
- ConnectionEvent fail;
- fail.set_payload(builder_to_string(std::move(builder)));
- per_connection_events_[current_connection_request_]->OnIncomingEvent(fail);
- current_connection_request_++;
- }
-
- class Connection : public ConnectionManagementCallbacks {
- public:
- Connection(uint16_t handle, std::shared_ptr<ClassicAclConnection> connection,
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<ConnectionEvent>> event_stream)
- : handle_(handle),
- connection_(std::move(connection)),
- event_stream_(std::move(event_stream)) {}
-
- ConnectionManagementCallbacks* GetCallbacks() { return this; }
-
- void OnCentralLinkKeyComplete(KeyFlag key_flag) override {
- log::info("key_flag:{}", KeyFlagText(key_flag));
- }
-
- void OnRoleChange(hci::ErrorCode /* hci_status */, Role new_role) override {
- log::info("new_role:{}", (uint8_t)new_role);
- }
-
- void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) override {
- log::info("link_policy_settings:{}", link_policy_settings);
- }
-
- void OnConnectionPacketTypeChanged(uint16_t packet_type) override {
- log::info("OnConnectionPacketTypeChanged packet_type:{}", packet_type);
- }
-
- void OnAuthenticationComplete(hci::ErrorCode /* hci_status */) override {
- log::info("OnAuthenticationComplete");
- }
-
- void OnEncryptionChange(EncryptionEnabled enabled) override {
- log::info("OnConnectionPacketTypeChanged enabled:{}", (uint8_t)enabled);
- }
-
- void OnChangeConnectionLinkKeyComplete() override {
- log::info("OnChangeConnectionLinkKeyComplete");
- }
-
- void OnReadClockOffsetComplete(uint16_t clock_offset) override {
- log::info("OnReadClockOffsetComplete clock_offset:{}", clock_offset);
- }
-
- void OnModeChange(ErrorCode /* status */, Mode current_mode, uint16_t interval) override {
- log::info("OnModeChange Mode:{}, interval:{}", (uint8_t)current_mode, interval);
- }
-
- void OnSniffSubrating(hci::ErrorCode /* hci_status */, uint16_t maximum_transmit_latency,
- uint16_t maximum_receive_latency, uint16_t minimum_remote_timeout,
- uint16_t minimum_local_timeout) override {
- log::info(
- "OnSniffSubrating maximum_transmit_latency:{}, maximum_receive_latency:{} "
- "minimum_remote_timeout:{} minimum_local_timeout:{}",
- maximum_transmit_latency, maximum_receive_latency, minimum_remote_timeout,
- minimum_local_timeout);
- }
-
- void OnQosSetupComplete(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
- uint32_t latency, uint32_t delay_variation) override {
- log::info(
- "OnQosSetupComplete service_type:{}, token_rate:{}, peak_bandwidth:{}, latency:{}, "
- "delay_variation:{}",
- (uint8_t)service_type, token_rate, peak_bandwidth, latency, delay_variation);
- }
-
- void OnFlowSpecificationComplete(FlowDirection flow_direction, ServiceType service_type,
- uint32_t token_rate, uint32_t token_bucket_size,
- uint32_t peak_bandwidth, uint32_t access_latency) override {
- log::info(
- "OnFlowSpecificationComplete flow_direction:{}. service_type:{}, token_rate:{}, "
- "token_bucket_size:{}, peak_bandwidth:{}, access_latency:{}",
- (uint8_t)flow_direction, (uint8_t)service_type, token_rate, token_bucket_size,
- peak_bandwidth, access_latency);
- }
-
- void OnFlushOccurred() override { log::info("OnFlushOccurred"); }
-
- void OnRoleDiscoveryComplete(Role current_role) override {
- log::info("OnRoleDiscoveryComplete current_role:{}", (uint8_t)current_role);
- }
-
- void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) override {
- log::info("OnReadAutomaticFlushTimeoutComplete flush_timeout:{}", flush_timeout);
- }
-
- void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {
- log::info("OnReadTransmitPowerLevelComplete transmit_power_level:{}", transmit_power_level);
- }
-
- void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {
- log::info("OnReadLinkSupervisionTimeoutComplete link_supervision_timeout:{}",
- link_supervision_timeout);
- }
-
- void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {
- log::info("OnReadFailedContactCounterComplete failed_contact_counter:{}",
- failed_contact_counter);
- }
-
- void OnReadLinkQualityComplete(uint8_t link_quality) override {
- log::info("OnReadLinkQualityComplete link_quality:{}", link_quality);
- }
-
- void OnReadAfhChannelMapComplete(AfhMode afh_mode,
- std::array<uint8_t, 10> /* afh_channel_map */) override {
- log::info("OnReadAfhChannelMapComplete afh_mode:{}", (uint8_t)afh_mode);
- }
-
- void OnReadRssiComplete(uint8_t rssi) override {
- log::info("OnReadRssiComplete rssi:{}", rssi);
- }
-
- void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {
- log::info("OnReadClockComplete clock:{}, accuracy:{}", clock, accuracy);
- }
-
- void OnDisconnection(ErrorCode reason) override {
- log::info("reason: {}", ErrorCodeText(reason));
- std::unique_ptr<BasePacketBuilder> builder =
- DisconnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, reason);
- ConnectionEvent disconnection;
- disconnection.set_payload(builder_to_string(std::move(builder)));
- event_stream_->OnIncomingEvent(disconnection);
- }
- void OnReadRemoteVersionInformationComplete(hci::ErrorCode /* error_status */,
- uint8_t lmp_version, uint16_t manufacturer_name,
- uint16_t sub_version) override {
- log::info(
- "OnReadRemoteVersionInformationComplete lmp_version:{} manufacturer_name:{} "
- "sub_version:{}",
- lmp_version, manufacturer_name, sub_version);
- }
- void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {
- log::info("OnReadRemoteSupportedFeaturesComplete features:0x{:x}", features);
- }
- void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number,
- uint64_t features) override {
- log::info(
- "OnReadRemoteExtendedFeaturesComplete page_number:{} max_page_number:{} "
- "features:0x{:x}",
- page_number, max_page_number, features);
- }
-
- uint16_t handle_;
- std::shared_ptr<ClassicAclConnection> connection_;
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<ConnectionEvent>> event_stream_;
- ::bluetooth::grpc::GrpcEventQueue<AclData> pending_acl_data_{std::string("PendingAclData") +
- std::to_string(handle_)};
- };
-
-private:
- AclManager* acl_manager_;
- ::bluetooth::os::Handler* facade_handler_;
- mutable std::mutex acl_connections_mutex_;
- std::map<uint16_t, Connection> acl_connections_;
- std::vector<std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<ConnectionEvent>>>
- per_connection_events_;
- uint32_t current_connection_request_{0};
-};
-
-void AclManagerFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<AclManager>();
-}
-
-void AclManagerFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new AclManagerFacadeService(GetDependency<AclManager>(), GetHandler());
-}
-
-void AclManagerFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* AclManagerFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory AclManagerFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new AclManagerFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/acl_manager_facade.h b/system/gd/hci/facade/acl_manager_facade.h
deleted file mode 100644
index b55937db53..0000000000
--- a/system/gd/hci/facade/acl_manager_facade.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-#include "hci/acl_manager.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class AclManagerFacadeService;
-
-class AclManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- AclManagerFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/controller_facade.cc b/system/gd/hci/facade/controller_facade.cc
deleted file mode 100644
index ad8a4df217..0000000000
--- a/system/gd/hci/facade/controller_facade.cc
+++ /dev/null
@@ -1,185 +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 "hci/facade/controller_facade.h"
-
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-
-#include "blueberry/facade/hci/controller_facade.grpc.pb.h"
-#include "blueberry/facade/hci/controller_facade.pb.h"
-#include "common/bind.h"
-#include "common/blocking_queue.h"
-#include "grpc/grpc_event_queue.h"
-#include "hci/address.h"
-#include "hci/controller.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using namespace blueberry::facade::hci;
-using blueberry::facade::BluetoothAddress;
-
-class ControllerFacadeService : public ControllerFacade::Service {
-public:
- ControllerFacadeService(Controller* controller, ::bluetooth::os::Handler*)
- : controller_(controller) {}
-
- ::grpc::Status GetMacAddress(::grpc::ServerContext* /* context */,
- const ::google::protobuf::Empty* /* request */,
- BluetoothAddress* response) override {
- Address local_address = controller_->GetMacAddress();
- response->set_address(local_address.ToString());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status GetLocalName(::grpc::ServerContext* /* context */,
- const ::google::protobuf::Empty* /* request */,
- NameMsg* response) override {
- std::string local_name = controller_->GetLocalName();
- response->set_name(local_name);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status WriteLocalName(::grpc::ServerContext* /* context */, const NameMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- controller_->WriteLocalName(request->name());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status IsSupportedCommand(::grpc::ServerContext* /* context */, const OpCodeMsg* request,
- SupportedMsg* response) override {
- bool ret = controller_->IsSupported(static_cast<OpCode>(request->op_code()));
- response->set_supported(ret);
- return ::grpc::Status::OK;
- }
-
-#define SUPPORTED_API(name) \
- ::grpc::Status name(::grpc::ServerContext* /* context */, \
- const ::google::protobuf::Empty* /* request */, SupportedMsg* response) \
- override { \
- response->set_supported(controller_->name()); \
- return ::grpc::Status::OK; \
- }
-
- SUPPORTED_API(SupportsSimplePairing)
- SUPPORTED_API(SupportsSecureConnections)
- SUPPORTED_API(SupportsSimultaneousLeBrEdr)
- SUPPORTED_API(SupportsInterlacedInquiryScan)
- SUPPORTED_API(SupportsRssiWithInquiryResults)
- SUPPORTED_API(SupportsExtendedInquiryResponse)
- SUPPORTED_API(SupportsRoleSwitch)
- SUPPORTED_API(Supports3SlotPackets)
- SUPPORTED_API(Supports5SlotPackets)
- SUPPORTED_API(SupportsClassic2mPhy)
- SUPPORTED_API(SupportsClassic3mPhy)
- SUPPORTED_API(Supports3SlotEdrPackets)
- SUPPORTED_API(Supports5SlotEdrPackets)
- SUPPORTED_API(SupportsSco)
- SUPPORTED_API(SupportsHv2Packets)
- SUPPORTED_API(SupportsHv3Packets)
- SUPPORTED_API(SupportsEv3Packets)
- SUPPORTED_API(SupportsEv4Packets)
- SUPPORTED_API(SupportsEv5Packets)
- SUPPORTED_API(SupportsEsco2mPhy)
- SUPPORTED_API(SupportsEsco3mPhy)
- SUPPORTED_API(Supports3SlotEscoEdrPackets)
- SUPPORTED_API(SupportsHoldMode)
- SUPPORTED_API(SupportsSniffMode)
- SUPPORTED_API(SupportsParkMode)
- SUPPORTED_API(SupportsNonFlushablePb)
- SUPPORTED_API(SupportsSniffSubrating)
- SUPPORTED_API(SupportsEncryptionPause)
- SUPPORTED_API(SupportsBle)
- SUPPORTED_API(SupportsBleEncryption)
- SUPPORTED_API(SupportsBleConnectionParametersRequest)
- SUPPORTED_API(SupportsBleExtendedReject)
- SUPPORTED_API(SupportsBlePeripheralInitiatedFeaturesExchange)
- SUPPORTED_API(SupportsBlePing)
- SUPPORTED_API(SupportsBleDataPacketLengthExtension)
- SUPPORTED_API(SupportsBlePrivacy)
- SUPPORTED_API(SupportsBleExtendedScannerFilterPolicies)
- SUPPORTED_API(SupportsBle2mPhy)
- SUPPORTED_API(SupportsBleStableModulationIndexTx)
- SUPPORTED_API(SupportsBleStableModulationIndexRx)
- SUPPORTED_API(SupportsBleCodedPhy)
- SUPPORTED_API(SupportsBleExtendedAdvertising)
- SUPPORTED_API(SupportsBlePeriodicAdvertising)
- SUPPORTED_API(SupportsBleChannelSelectionAlgorithm2)
- SUPPORTED_API(SupportsBlePowerClass1)
- SUPPORTED_API(SupportsBleMinimumUsedChannels)
- SUPPORTED_API(SupportsBleConnectionCteRequest)
- SUPPORTED_API(SupportsBleConnectionCteResponse)
- SUPPORTED_API(SupportsBleConnectionlessCteTransmitter)
- SUPPORTED_API(SupportsBleConnectionlessCteReceiver)
- SUPPORTED_API(SupportsBleAntennaSwitchingDuringCteTx)
- SUPPORTED_API(SupportsBleAntennaSwitchingDuringCteRx)
- SUPPORTED_API(SupportsBleReceivingConstantToneExtensions)
- SUPPORTED_API(SupportsBlePeriodicAdvertisingSyncTransferSender)
- SUPPORTED_API(SupportsBlePeriodicAdvertisingSyncTransferRecipient)
- SUPPORTED_API(SupportsBleSleepClockAccuracyUpdates)
- SUPPORTED_API(SupportsBleRemotePublicKeyValidation)
- SUPPORTED_API(SupportsBleConnectedIsochronousStreamCentral)
- SUPPORTED_API(SupportsBleConnectedIsochronousStreamPeripheral)
- SUPPORTED_API(SupportsBleIsochronousBroadcaster)
- SUPPORTED_API(SupportsBleSynchronizedReceiver)
- SUPPORTED_API(SupportsBleIsochronousChannelsHostSupport)
- SUPPORTED_API(SupportsBlePowerControlRequest)
- SUPPORTED_API(SupportsBlePowerChangeIndication)
- SUPPORTED_API(SupportsBlePathLossMonitoring)
- SUPPORTED_API(SupportsBlePeriodicAdvertisingAdi)
-
- ::grpc::Status GetLeNumberOfSupportedAdvertisingSets(
- ::grpc::ServerContext* /* context */, const ::google::protobuf::Empty* /* request */,
- SingleValueMsg* response) override {
- uint8_t ret = controller_->GetLeNumberOfSupportedAdverisingSets();
- response->set_value(ret);
- return ::grpc::Status::OK;
- }
-
-private:
- Controller* controller_;
-};
-
-void ControllerFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<Controller>();
-}
-
-void ControllerFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new ControllerFacadeService(GetDependency<Controller>(), GetHandler());
-}
-
-void ControllerFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* ControllerFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory ControllerFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new ControllerFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/controller_facade.h b/system/gd/hci/facade/controller_facade.h
deleted file mode 100644
index 2017b10722..0000000000
--- a/system/gd/hci/facade/controller_facade.h
+++ /dev/null
@@ -1,45 +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.
- */
-
-#pragma once
-
-#include <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-#include "hci/controller.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class ControllerFacadeService;
-
-class ControllerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- ControllerFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/facade.cc b/system/gd/hci/facade/facade.cc
deleted file mode 100644
index 7d9d97eaf8..0000000000
--- a/system/gd/hci/facade/facade.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2019 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 "hci/facade/facade.h"
-
-#include <bluetooth/log.h>
-
-#include <memory>
-
-#include "blueberry/facade/hci/hci_facade.grpc.pb.h"
-#include "common/bind.h"
-#include "grpc/grpc_event_queue.h"
-#include "hci/controller.h"
-#include "hci/hci_layer.h"
-#include "hci/hci_packets.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using namespace blueberry::facade::hci;
-
-class HciFacadeService : public HciFacade::Service {
-public:
- HciFacadeService(HciLayer* hci_layer, Controller* controller,
- ::bluetooth::os::Handler* facade_handler)
- : hci_layer_(hci_layer), controller_(controller), facade_handler_(facade_handler) {}
-
- virtual ~HciFacadeService() {
- if (unregister_acl_dequeue_) {
- hci_layer_->GetAclQueueEnd()->UnregisterDequeue();
- }
- if (waiting_acl_packet_ != nullptr) {
- hci_layer_->GetAclQueueEnd()->UnregisterEnqueue();
- if (waiting_acl_packet_ != nullptr) {
- waiting_acl_packet_.reset();
- }
- }
- }
-
- class TestCommandBuilder : public CommandBuilder {
- public:
- explicit TestCommandBuilder(std::vector<uint8_t> bytes)
- : CommandBuilder(OpCode::NONE), bytes_(std::move(bytes)) {}
- size_t size() const override { return bytes_.size(); }
- void Serialize(BitInserter& bit_inserter) const override {
- for (auto&& b : bytes_) {
- bit_inserter.insert_byte(b);
- }
- }
-
- private:
- std::vector<uint8_t> bytes_;
- };
-
- ::grpc::Status SendCommand(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::Data* command,
- ::google::protobuf::Empty* /* response */) override {
- auto payload = std::vector<uint8_t>(command->payload().begin(), command->payload().end());
- auto packet = std::make_unique<TestCommandBuilder>(payload);
- auto opcode = static_cast<const bluetooth::hci::OpCode>(payload.at(1) << 8 | payload.at(0));
- if (Checker::IsCommandStatusOpcode(opcode)) {
- hci_layer_->EnqueueCommand(std::move(packet),
- facade_handler_->BindOnceOn(this, &HciFacadeService::on_status));
- } else {
- hci_layer_->EnqueueCommand(std::move(packet),
- facade_handler_->BindOnceOn(this, &HciFacadeService::on_complete));
- }
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status RequestEvent(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::hci::EventRequest* event,
- ::google::protobuf::Empty* /* response */) override {
- hci_layer_->RegisterEventHandler(static_cast<EventCode>(event->code()),
- facade_handler_->BindOn(this, &HciFacadeService::on_event));
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status RequestLeSubevent(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::hci::EventRequest* event,
- ::google::protobuf::Empty* /* response */) override {
- hci_layer_->RegisterLeEventHandler(
- static_cast<SubeventCode>(event->code()),
- facade_handler_->BindOn(this, &HciFacadeService::on_le_subevent));
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status StreamEvents(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- return pending_events_.RunLoop(context, writer);
- }
-
- ::grpc::Status StreamLeSubevents(
- ::grpc::ServerContext* context, const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- return pending_le_events_.RunLoop(context, writer);
- }
-
- class TestAclBuilder : public AclBuilder {
- public:
- explicit TestAclBuilder(std::vector<uint8_t> payload)
- : AclBuilder(0xbad, PacketBoundaryFlag::CONTINUING_FRAGMENT,
- BroadcastFlag::ACTIVE_PERIPHERAL_BROADCAST),
- bytes_(std::move(payload)) {}
-
- size_t size() const override { return bytes_.size(); }
- void Serialize(BitInserter& bit_inserter) const override {
- for (auto&& b : bytes_) {
- bit_inserter.insert_byte(b);
- }
- }
-
- private:
- std::vector<uint8_t> bytes_;
- };
-
- ::grpc::Status SendAcl(::grpc::ServerContext* /* context */, const ::blueberry::facade::Data* acl,
- ::google::protobuf::Empty* /* response */) override {
- waiting_acl_packet_ = std::make_unique<TestAclBuilder>(
- std::vector<uint8_t>(acl->payload().begin(), acl->payload().end()));
- std::promise<void> enqueued;
- auto future = enqueued.get_future();
- if (!completed_packets_callback_registered_) {
- controller_->RegisterCompletedAclPacketsCallback(
- facade_handler_->Bind([](uint16_t, uint16_t) { /* do nothing */ }));
- completed_packets_callback_registered_ = true;
- }
- hci_layer_->GetAclQueueEnd()->RegisterEnqueue(
- facade_handler_, common::Bind(&HciFacadeService::handle_enqueue_acl,
- common::Unretained(this), common::Unretained(&enqueued)));
- auto result = future.wait_for(std::chrono::milliseconds(100));
- log::assert_that(std::future_status::ready == result,
- "assert failed: std::future_status::ready == result");
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status StreamAcl(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<::blueberry::facade::Data>* writer) override {
- hci_layer_->GetAclQueueEnd()->RegisterDequeue(
- facade_handler_,
- common::Bind(&HciFacadeService::on_acl_ready, common::Unretained(this)));
- unregister_acl_dequeue_ = true;
- return pending_acl_events_.RunLoop(context, writer);
- }
-
-private:
- std::unique_ptr<AclBuilder> handle_enqueue_acl(std::promise<void>* promise) {
- promise->set_value();
- hci_layer_->GetAclQueueEnd()->UnregisterEnqueue();
- return std::move(waiting_acl_packet_);
- }
-
- void on_acl_ready() {
- auto acl_ptr = hci_layer_->GetAclQueueEnd()->TryDequeue();
- log::assert_that(acl_ptr != nullptr, "assert failed: acl_ptr != nullptr");
- log::assert_that(acl_ptr->IsValid(), "assert failed: acl_ptr->IsValid()");
- log::info("Got an Acl message for handle 0x{:x}", acl_ptr->GetHandle());
- ::blueberry::facade::Data incoming;
- incoming.set_payload(std::string(acl_ptr->begin(), acl_ptr->end()));
- pending_acl_events_.OnIncomingEvent(std::move(incoming));
- }
-
- void on_event(hci::EventView view) {
- log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
- log::info("Got an Event {}", EventCodeText(view.GetEventCode()));
- ::blueberry::facade::Data response;
- response.set_payload(std::string(view.begin(), view.end()));
- pending_events_.OnIncomingEvent(std::move(response));
- }
-
- void on_le_subevent(hci::LeMetaEventView view) {
- log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
- log::info("Got an LE Event {}", SubeventCodeText(view.GetSubeventCode()));
- ::blueberry::facade::Data response;
- response.set_payload(std::string(view.begin(), view.end()));
- pending_le_events_.OnIncomingEvent(std::move(response));
- }
-
- void on_complete(hci::CommandCompleteView view) {
- log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
- log::info("Got a Command complete {}", OpCodeText(view.GetCommandOpCode()));
- ::blueberry::facade::Data response;
- response.set_payload(std::string(view.begin(), view.end()));
- pending_events_.OnIncomingEvent(std::move(response));
- }
-
- void on_status(hci::CommandStatusView view) {
- log::assert_that(view.IsValid(), "assert failed: view.IsValid()");
- log::info("Got a Command status {}", OpCodeText(view.GetCommandOpCode()));
- ::blueberry::facade::Data response;
- response.set_payload(std::string(view.begin(), view.end()));
- pending_events_.OnIncomingEvent(std::move(response));
- }
-
- HciLayer* hci_layer_;
- Controller* controller_;
- ::bluetooth::os::Handler* facade_handler_;
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_events_{"StreamEvents"};
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_le_events_{
- "StreamLeSubevents"};
- ::bluetooth::grpc::GrpcEventQueue<::blueberry::facade::Data> pending_acl_events_{"StreamAcl"};
- bool unregister_acl_dequeue_{false};
- std::unique_ptr<TestAclBuilder> waiting_acl_packet_;
- bool completed_packets_callback_registered_{false};
-};
-
-void HciFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<HciLayer>();
- list->add<Controller>();
-}
-
-void HciFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new HciFacadeService(GetDependency<HciLayer>(), GetDependency<Controller>(),
- GetHandler());
-}
-
-void HciFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* HciFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory HciFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new HciFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/facade.h b/system/gd/hci/facade/facade.h
deleted file mode 100644
index 283908ddac..0000000000
--- a/system/gd/hci/facade/facade.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-#include "hci/hci_layer.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class HciFacadeService;
-
-class HciFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- HciFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_acl_manager_facade.cc b/system/gd/hci/facade/le_acl_manager_facade.cc
deleted file mode 100644
index 3e7ff96892..0000000000
--- a/system/gd/hci/facade/le_acl_manager_facade.cc
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright 2019 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 "hci/facade/le_acl_manager_facade.h"
-
-#include <bluetooth/log.h>
-
-#include <memory>
-#include <mutex>
-
-#include "blueberry/facade/hci/le_acl_manager_facade.grpc.pb.h"
-#include "blueberry/facade/hci/le_acl_manager_facade.pb.h"
-#include "common/bind.h"
-#include "grpc/grpc_event_queue.h"
-#include "hci/acl_manager.h"
-#include "hci/hci_packets.h"
-#include "hci/octets.h"
-#include "packet/raw_builder.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-using ::bluetooth::packet::RawBuilder;
-
-namespace std {
-template <>
-struct formatter<blueberry::facade::BluetoothAddressTypeEnum>
- : enum_formatter<blueberry::facade::BluetoothAddressTypeEnum> {};
-} // namespace std
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using acl_manager::LeAclConnection;
-using acl_manager::LeConnectionCallbacks;
-using acl_manager::LeConnectionManagementCallbacks;
-
-using namespace blueberry::facade::hci;
-
-class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeConnectionCallbacks {
-public:
- LeAclManagerFacadeService(AclManager* acl_manager, ::bluetooth::os::Handler* facade_handler)
- : acl_manager_(acl_manager), facade_handler_(facade_handler) {
- acl_manager_->RegisterLeCallbacks(this, facade_handler_);
- }
-
- ~LeAclManagerFacadeService() {
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- for (auto& conn : acl_connections_) {
- if (conn.second.connection_ != nullptr) {
- conn.second.connection_->GetAclQueueEnd()->UnregisterDequeue();
- conn.second.connection_.reset();
- }
- }
- }
-
- ::grpc::Status CreateConnection(::grpc::ServerContext* context,
- const CreateConnectionMsg* request,
- ::grpc::ServerWriter<LeConnectionEvent>* writer) override {
- log::info("peer={}, type={}, id_direct={}", request->peer_address().address().address(),
- request->peer_address().type(), request->is_direct());
- Address peer_address;
- log::assert_that(
- Address::FromString(request->peer_address().address().address(), peer_address),
- "assert failed: Address::FromString(request->peer_address().address().address(), "
- "peer_address)");
- AddressWithType peer(peer_address, static_cast<AddressType>(request->peer_address().type()));
- bool is_direct = request->is_direct();
- acl_manager_->CreateLeConnection(peer, is_direct);
-
- if (is_direct) {
- if (direct_connection_events_ != nullptr) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Only one outstanding direct request is supported");
- }
- direct_connection_events_ =
- std::make_shared<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
- std::string("direct connection attempt ") + peer.ToString());
- direct_connection_address_ = peer;
- return direct_connection_events_->RunLoop(context, writer);
- }
- per_connection_events_.emplace(
- peer, std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
- std::string("connection attempt ") + peer.ToString()));
- return per_connection_events_[peer]->RunLoop(context, writer);
- }
-
- ::grpc::Status CancelConnection(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::BluetoothAddressWithType* request,
- google::protobuf::Empty* /* response */) override {
- log::info("peer={}, type={}", request->address().address(), request->type());
- Address peer_address;
- log::assert_that(
- Address::FromString(request->address().address(), peer_address),
- "assert failed: Address::FromString(request->address().address(), peer_address)");
- AddressWithType peer(peer_address, static_cast<AddressType>(request->type()));
- if (peer == direct_connection_address_) {
- direct_connection_address_ = AddressWithType();
- direct_connection_events_.reset();
- } else {
- if (per_connection_events_.count(peer) == 0) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT,
- "No matching outstanding connection");
- }
- }
- acl_manager_->CancelLeConnect(peer);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status Disconnect(::grpc::ServerContext* /* context */, const LeHandleMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("handle={}", request->handle());
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- log::error("Invalid handle");
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- } else {
- connection->second.connection_->Disconnect(
- DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
- return ::grpc::Status::OK;
- }
- }
-
-#define GET_CONNECTION(view) \
- std::map<uint16_t, Connection>::iterator connection; \
- do { \
- if (!view.IsValid()) { \
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle"); \
- } \
- std::unique_lock<std::mutex> lock(acl_connections_mutex_); \
- connection = acl_connections_.find(view.GetConnectionHandle()); \
- if (connection == acl_connections_.end()) { \
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle"); \
- } \
- } while (0)
-
- ::grpc::Status ConnectionCommand(::grpc::ServerContext* /* context */,
- const LeConnectionCommandMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("size={}", request->packet().size());
- auto command_view = ConnectionManagementCommandView::Create(AclCommandView::Create(
- CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>(
- request->packet().begin(), request->packet().end())))));
- if (!command_view.IsValid()) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid command packet");
- }
- log::info("opcode={}", OpCodeText(command_view.GetOpCode()));
- switch (command_view.GetOpCode()) {
- case OpCode::DISCONNECT: {
- auto view = DisconnectView::Create(command_view);
- GET_CONNECTION(view);
- connection->second.connection_->Disconnect(view.GetReason());
- return ::grpc::Status::OK;
- }
- default:
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid command packet");
- }
- }
-#undef GET_CONNECTION
-
- ::grpc::Status FetchIncomingConnection(::grpc::ServerContext* context,
- const google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<LeConnectionEvent>* writer) override {
- log::info("wait for one incoming connection");
- if (incoming_connection_events_ != nullptr) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Only one outstanding incoming connection is supported");
- }
- incoming_connection_events_ =
- std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>(
- std::string("incoming connection "));
- return incoming_connection_events_->RunLoop(context, writer);
- }
-
- ::grpc::Status AddDeviceToResolvingList(::grpc::ServerContext* /* context */,
- const IrkMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("peer={}, type={}", request->peer().address().address(), request->peer().type());
- Address peer_address;
- log::assert_that(Address::FromString(request->peer().address().address(), peer_address),
- "assert failed: Address::FromString(request->peer().address().address(), "
- "peer_address)");
- AddressWithType peer(peer_address, static_cast<AddressType>(request->peer().type()));
-
- auto request_peer_irk_length = request->peer_irk().end() - request->peer_irk().begin();
-
- if (request_peer_irk_length != kOctet16Length) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid Peer IRK");
- }
-
- auto request_local_irk_length = request->local_irk().end() - request->local_irk().begin();
- if (request_local_irk_length != kOctet16Length) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid Local IRK");
- }
-
- Octet16 peer_irk = {};
- Octet16 local_irk = {};
-
- std::vector<uint8_t> peer_irk_data(request->peer_irk().begin(), request->peer_irk().end());
- std::copy_n(peer_irk_data.begin(), kOctet16Length, peer_irk.begin());
-
- std::vector<uint8_t> local_irk_data(request->local_irk().begin(), request->local_irk().end());
- std::copy_n(local_irk_data.begin(), kOctet16Length, local_irk.begin());
-
- acl_manager_->AddDeviceToResolvingList(peer, peer_irk, local_irk);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SendAclData(::grpc::ServerContext* /* context */, const LeAclData* request,
- ::google::protobuf::Empty* /* response */) override {
- log::info("handle={}, size={}", request->handle(), request->payload().size());
- std::promise<void> promise;
- auto future = promise.get_future();
- {
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- }
- connection->second.connection_->GetAclQueueEnd()->RegisterEnqueue(
- facade_handler_,
- common::Bind(&LeAclManagerFacadeService::enqueue_packet, common::Unretained(this),
- common::Unretained(request), common::Passed(std::move(promise))));
- auto status = future.wait_for(std::chrono::milliseconds(1000));
- if (status != std::future_status::ready) {
- return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Can't send packet");
- }
- }
- return ::grpc::Status::OK;
- }
-
- std::unique_ptr<BasePacketBuilder> enqueue_packet(const LeAclData* request,
- std::promise<void> promise) {
- auto connection = acl_connections_.find(request->handle());
- log::assert_that(connection != acl_connections_.end(), "handle {}", request->handle());
- connection->second.connection_->GetAclQueueEnd()->UnregisterEnqueue();
- std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>(
- std::vector<uint8_t>(request->payload().begin(), request->payload().end()));
- promise.set_value();
- return packet;
- }
-
- ::grpc::Status FetchAclData(::grpc::ServerContext* context, const LeHandleMsg* request,
- ::grpc::ServerWriter<LeAclData>* writer) override {
- log::info("handle={}", request->handle());
- auto connection = acl_connections_.find(request->handle());
- if (connection == acl_connections_.end()) {
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid handle");
- }
- return connection->second.pending_acl_data_.RunLoop(context, writer);
- }
-
- static inline std::string builder_to_string(std::unique_ptr<BasePacketBuilder> builder) {
- std::vector<uint8_t> bytes;
- BitInserter bit_inserter(bytes);
- builder->Serialize(bit_inserter);
- return std::string(bytes.begin(), bytes.end());
- }
-
- void on_incoming_acl(std::shared_ptr<LeAclConnection> connection, uint16_t handle) {
- log::info("handle={}, addr={}", connection->GetHandle(), connection->GetRemoteAddress());
- auto packet = connection->GetAclQueueEnd()->TryDequeue();
- auto connection_tracker = acl_connections_.find(handle);
- log::assert_that(connection_tracker != acl_connections_.end(), "handle {}", handle);
- LeAclData acl_data;
- acl_data.set_handle(handle);
- acl_data.set_payload(std::string(packet->begin(), packet->end()));
- connection_tracker->second.pending_acl_data_.OnIncomingEvent(acl_data);
- }
-
- void OnLeConnectSuccess(AddressWithType peer,
- std::unique_ptr<LeAclConnection> connection) override {
- log::info("handle={}, addr={}", connection->GetHandle(), peer);
- std::unique_lock<std::mutex> lock(acl_connections_mutex_);
- std::shared_ptr<LeAclConnection> shared_connection = std::move(connection);
- uint16_t handle = shared_connection->GetHandle();
- auto role = shared_connection->GetRole();
- if (role == Role::PERIPHERAL) {
- log::assert_that(incoming_connection_events_ != nullptr,
- "assert failed: incoming_connection_events_ != nullptr");
- if (per_connection_events_.find(peer) == per_connection_events_.end()) {
- per_connection_events_.emplace(peer, incoming_connection_events_);
- } else {
- per_connection_events_[peer] = incoming_connection_events_;
- }
- incoming_connection_events_.reset();
- } else if (direct_connection_address_ == peer) {
- direct_connection_address_ = AddressWithType();
- per_connection_events_.emplace(peer, direct_connection_events_);
- direct_connection_events_.reset();
- } else {
- log::assert_that(per_connection_events_.count(peer) > 0, "No connection request for {}",
- ADDRESS_TO_LOGGABLE_CSTR(peer));
- }
- acl_connections_.erase(handle);
- acl_connections_.emplace(
- std::piecewise_construct, std::forward_as_tuple(handle),
- std::forward_as_tuple(handle, shared_connection, per_connection_events_[peer]));
- shared_connection->GetAclQueueEnd()->RegisterDequeue(
- facade_handler_, common::Bind(&LeAclManagerFacadeService::on_incoming_acl,
- common::Unretained(this), shared_connection, handle));
- auto callbacks = acl_connections_.find(handle)->second.GetCallbacks();
- shared_connection->RegisterCallbacks(callbacks, facade_handler_);
- {
- std::unique_ptr<BasePacketBuilder> builder = LeConnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, handle, role, peer.GetAddressType(), peer.GetAddress(), 1, 2, 3,
- ClockAccuracy::PPM_20);
- LeConnectionEvent success;
- success.set_payload(builder_to_string(std::move(builder)));
- per_connection_events_[peer]->OnIncomingEvent(success);
- }
- }
-
- void OnLeConnectFail(AddressWithType address, ErrorCode reason) override {
- log::info("addr={}, reason={}", address, ErrorCodeText(reason));
- std::unique_ptr<BasePacketBuilder> builder = LeConnectionCompleteBuilder::Create(
- reason, 0, Role::CENTRAL, address.GetAddressType(), address.GetAddress(), 0, 0, 0,
- ClockAccuracy::PPM_20);
- LeConnectionEvent fail;
- fail.set_payload(builder_to_string(std::move(builder)));
- if (address == direct_connection_address_) {
- direct_connection_address_ = AddressWithType();
- direct_connection_events_->OnIncomingEvent(fail);
- } else {
- per_connection_events_[address]->OnIncomingEvent(fail);
- }
- }
-
- class Connection : public LeConnectionManagementCallbacks {
- public:
- Connection(uint16_t handle, std::shared_ptr<LeAclConnection> connection,
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> event_stream)
- : handle_(handle),
- connection_(std::move(connection)),
- event_stream_(std::move(event_stream)) {}
- void OnConnectionUpdate(hci::ErrorCode /* hci_status */, uint16_t connection_interval,
- uint16_t connection_latency, uint16_t supervision_timeout) override {
- log::info("interval: 0x{:x}, latency: 0x{:x}, timeout 0x{:x}", connection_interval,
- connection_latency, supervision_timeout);
- }
-
- void OnParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t latency,
- uint16_t supervision_timeout) override {
- log::info("interval_min: 0x{:x}, interval_max: 0x{:x}, latency: 0x{:x}, timeout 0x{:x}",
- interval_min, interval_max, latency, supervision_timeout);
- }
-
- void OnDataLengthChange(uint16_t tx_octets, uint16_t tx_time, uint16_t rx_octets,
- uint16_t rx_time) override {
- log::info("tx_octets: 0x{:x}, tx_time: 0x{:x}, rx_octets 0x{:x}, rx_time 0x{:x}", tx_octets,
- tx_time, rx_octets, rx_time);
- }
-
- void OnPhyUpdate(hci::ErrorCode /* hci_status */, uint8_t /* tx_phy */,
- uint8_t /* rx_phy */) override {}
- void OnDisconnection(ErrorCode reason) override {
- log::info("reason: {}", ErrorCodeText(reason));
- std::unique_ptr<BasePacketBuilder> builder =
- DisconnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, reason);
- LeConnectionEvent disconnection;
- disconnection.set_payload(builder_to_string(std::move(builder)));
- event_stream_->OnIncomingEvent(disconnection);
- }
-
- void OnReadRemoteVersionInformationComplete(hci::ErrorCode /* hci_status */,
- uint8_t /* lmp_version */,
- uint16_t /* manufacturer_name */,
- uint16_t /* sub_version */) override {}
- void OnLeReadRemoteFeaturesComplete(hci::ErrorCode /* hci_status */,
- uint64_t /* features */) override {}
-
- LeConnectionManagementCallbacks* GetCallbacks() { return this; }
- void OnLeSubrateChange(hci::ErrorCode hci_status, uint16_t subrate_factor,
- uint16_t peripheral_latency, uint16_t continuation_number,
- uint16_t supervision_timeout) override {
- log::info(
- "hci_status: {}, subrate_factor: {:#x}, peripheral_latency: {:#x}, "
- "continuation_number: "
- "{:#x}, supervision_timeout: {:#x}",
- ErrorCodeText(hci_status), subrate_factor, peripheral_latency, continuation_number,
- supervision_timeout);
- }
-
- uint16_t handle_;
- std::shared_ptr<LeAclConnection> connection_;
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> event_stream_;
- ::bluetooth::grpc::GrpcEventQueue<LeAclData> pending_acl_data_{std::string("PendingAclData") +
- std::to_string(handle_)};
- };
-
- ::grpc::Status IsOnBackgroundList(::grpc::ServerContext* /* context */,
- const ::blueberry::facade::hci::BackgroundRequestMsg* request,
- ::blueberry::facade::hci::BackgroundResultMsg* msg) {
- Address peer_address;
- log::assert_that(
- Address::FromString(request->peer_address().address().address(), peer_address),
- "assert failed: Address::FromString(request->peer_address().address().address(), "
- "peer_address)");
- AddressWithType peer(peer_address, static_cast<AddressType>(request->peer_address().type()));
- std::promise<bool> promise;
- auto future = promise.get_future();
- acl_manager_->IsOnBackgroundList(peer, std::move(promise));
- msg->set_is_on_background_list(future.get());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status RemoveFromBackgroundList(
- ::grpc::ServerContext* /* context */,
- const ::blueberry::facade::hci::BackgroundRequestMsg* request,
- ::google::protobuf::Empty* /* response */) {
- Address peer_address;
- log::assert_that(
- Address::FromString(request->peer_address().address().address(), peer_address),
- "assert failed: Address::FromString(request->peer_address().address().address(), "
- "peer_address)");
- AddressWithType peer(peer_address, static_cast<AddressType>(request->peer_address().type()));
- acl_manager_->RemoveFromBackgroundList(peer);
- return ::grpc::Status::OK;
- }
-
-private:
- AclManager* acl_manager_;
- ::bluetooth::os::Handler* facade_handler_;
- mutable std::mutex acl_connections_mutex_;
- std::map<bluetooth::hci::AddressWithType,
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>>
- per_connection_events_;
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> direct_connection_events_;
- bluetooth::hci::AddressWithType direct_connection_address_;
- std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>> incoming_connection_events_;
- std::map<uint16_t, Connection> acl_connections_;
-};
-
-void LeAclManagerFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<AclManager>();
-}
-
-void LeAclManagerFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new LeAclManagerFacadeService(GetDependency<AclManager>(), GetHandler());
-}
-
-void LeAclManagerFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* LeAclManagerFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory LeAclManagerFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new LeAclManagerFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_acl_manager_facade.h b/system/gd/hci/facade/le_acl_manager_facade.h
deleted file mode 100644
index 931601c273..0000000000
--- a/system/gd/hci/facade/le_acl_manager_facade.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-#include "hci/acl_manager.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class LeAclManagerFacadeService;
-
-class LeAclManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- LeAclManagerFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_advertising_manager_facade.cc b/system/gd/hci/facade/le_advertising_manager_facade.cc
deleted file mode 100644
index 55ef78ce79..0000000000
--- a/system/gd/hci/facade/le_advertising_manager_facade.cc
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * Copyright 2019 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 "hci/facade/le_advertising_manager_facade.h"
-
-#include <bluetooth/log.h>
-
-#include <cstdint>
-#include <unordered_map>
-#include <utility>
-
-#include "blueberry/facade/hci/le_advertising_manager_facade.grpc.pb.h"
-#include "blueberry/facade/hci/le_advertising_manager_facade.pb.h"
-#include "common/bidi_queue.h"
-#include "common/bind.h"
-#include "grpc/grpc_event_queue.h"
-#include "hardware/ble_advertiser.h"
-#include "hci/address.h"
-#include "hci/address_with_type.h"
-#include "hci/le_advertising_manager.h"
-
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-using ::grpc::ServerWriter;
-using ::grpc::Status;
-
-using ::blueberry::facade::BluetoothAddress;
-using ::blueberry::facade::BluetoothAddressTypeEnum;
-using ::blueberry::facade::BluetoothOwnAddressTypeEnum;
-using ::blueberry::facade::hci::AdvertisingConfig;
-using ::blueberry::facade::hci::ExtendedAdvertisingConfig;
-using ::blueberry::facade::hci::GapDataMsg;
-using ::blueberry::facade::hci::PeriodicAdvertisingParameters;
-
-hci::GapData GapDataFromProto(const GapDataMsg& gap_data_proto) {
- hci::GapData gap_data;
- auto data_copy = std::make_shared<std::vector<uint8_t>>(gap_data_proto.data().begin(),
- gap_data_proto.data().end());
- packet::PacketView<packet::kLittleEndian> packet(data_copy);
- auto after = hci::GapData::Parse(&gap_data, packet.begin());
- log::assert_that(after != packet.begin(), "assert failed: after != packet.begin()");
- return gap_data;
-}
-
-bool AdvertisingConfigFromProto(const AdvertisingConfig& config_proto,
- hci::AdvertisingConfig* config) {
- for (const auto& elem : config_proto.advertisement()) {
- config->advertisement.push_back(GapDataFromProto(elem));
- }
-
- for (const auto& elem : config_proto.scan_response()) {
- config->scan_response.push_back(GapDataFromProto(elem));
- }
-
- if (config_proto.interval_min() > UINT16_MAX || config_proto.interval_min() < 0) {
- log::warn("Bad interval_min: {}", config_proto.interval_min());
- return false;
- }
- config->interval_min = static_cast<uint16_t>(config_proto.interval_min());
-
- if (config_proto.interval_max() > UINT16_MAX || config_proto.interval_max() < 0) {
- log::warn("Bad interval_max: {}", config_proto.interval_max());
- return false;
- }
- config->interval_max = static_cast<uint16_t>(config_proto.interval_max());
-
- config->advertising_type = static_cast<hci::AdvertisingType>(config_proto.advertising_type());
-
- config->requested_advertiser_address_type =
- config_proto.own_address_type() == BluetoothOwnAddressTypeEnum::USE_PUBLIC_DEVICE_ADDRESS
- ? AdvertiserAddressType::PUBLIC
- : AdvertiserAddressType::RESOLVABLE_RANDOM;
-
- config->peer_address_type =
- static_cast<::bluetooth::hci::PeerAddressType>(config_proto.peer_address_type());
-
- hci::Address::FromString(config_proto.peer_address().address(), config->peer_address);
-
- if (config_proto.channel_map() > UINT8_MAX || config_proto.channel_map() < 0) {
- log::warn("Bad channel_map: {}", config_proto.channel_map());
- return false;
- }
- config->channel_map = static_cast<uint8_t>(config_proto.channel_map());
-
- if (config_proto.tx_power() > UINT8_MAX || config_proto.tx_power() < 0) {
- log::warn("Bad tx_power: {}", config_proto.tx_power());
- return false;
- }
-
- config->filter_policy = static_cast<hci::AdvertisingFilterPolicy>(config_proto.filter_policy());
-
- config->tx_power = static_cast<uint8_t>(config_proto.tx_power());
-
- config->legacy_pdus = true;
-
- auto advertising_type =
- static_cast<::bluetooth::hci::AdvertisingType>(config_proto.advertising_type());
-
- switch (advertising_type) {
- case AdvertisingType::ADV_IND: {
- config->connectable = true;
- config->scannable = true;
- } break;
- case AdvertisingType::ADV_DIRECT_IND_HIGH: {
- config->connectable = true;
- config->directed = true;
- config->high_duty_cycle = true;
- } break;
- case AdvertisingType::ADV_SCAN_IND: {
- config->scannable = true;
- } break;
- case AdvertisingType::ADV_NONCONN_IND: {
- } break;
- case AdvertisingType::ADV_DIRECT_IND_LOW: {
- config->directed = true;
- config->connectable = true;
- } break;
- }
-
- return true;
-}
-
-bool ExtendedAdvertisingConfigFromProto(const ExtendedAdvertisingConfig& config_proto,
- hci::AdvertisingConfig* config) {
- if (!AdvertisingConfigFromProto(config_proto.advertising_config(), config)) {
- log::warn("Error parsing advertising config");
- return false;
- }
- config->connectable = config_proto.connectable();
- config->scannable = config_proto.scannable();
- config->directed = config_proto.directed();
- config->high_duty_cycle = config_proto.high_duty_directed_connectable();
- config->legacy_pdus = config_proto.legacy_pdus();
- config->anonymous = config_proto.anonymous();
- config->include_tx_power = config_proto.include_tx_power();
- config->use_le_coded_phy = config_proto.use_le_coded_phy();
- config->secondary_max_skip = static_cast<uint8_t>(config_proto.secondary_max_skip());
- config->secondary_advertising_phy =
- static_cast<hci::SecondaryPhyType>(config_proto.secondary_advertising_phy());
- config->sid = static_cast<uint8_t>(config_proto.sid());
- config->enable_scan_request_notifications =
- static_cast<hci::Enable>(config_proto.enable_scan_request_notifications());
- return true;
-}
-
-bool PeriodicAdvertisingParametersFromProto(const PeriodicAdvertisingParameters& config_proto,
- hci::PeriodicAdvertisingParameters* config) {
- if (config_proto.min_interval() > UINT16_MAX || config_proto.min_interval() < 0) {
- log::warn("Bad interval_min: {}", config_proto.min_interval());
- return false;
- }
- config->min_interval = static_cast<uint16_t>(config_proto.min_interval());
- if (config_proto.max_interval() > UINT16_MAX || config_proto.max_interval() < 0) {
- log::warn("Bad interval_max: {}", config_proto.max_interval());
- return false;
- }
- config->max_interval = static_cast<uint16_t>(config_proto.max_interval());
- config->properties = static_cast<hci::PeriodicAdvertisingParameters::AdvertisingProperty>(
- config_proto.advertising_property());
- return true;
-}
-
-class LeAdvertiser {
-public:
- LeAdvertiser(hci::AdvertisingConfig config) : config_(std::move(config)) {}
-
- void ScanCallback(Address /* address */, AddressType /* address_type */) {}
-
- void TerminatedCallback(ErrorCode /* error_code */, uint8_t, uint8_t) {}
-
- hci::AdvertiserId GetAdvertiserId() { return id_; }
-
- void SetAdvertiserId(hci::AdvertiserId id) { id_ = id; }
-
-private:
- hci::AdvertiserId id_ = LeAdvertisingManager::kInvalidId;
- hci::AdvertisingConfig config_;
-};
-
-using ::blueberry::facade::hci::AddressMsg;
-using ::blueberry::facade::hci::AdvertisingCallbackMsg;
-using ::blueberry::facade::hci::AdvertisingCallbackMsgType;
-using ::blueberry::facade::hci::AdvertisingStatus;
-using ::blueberry::facade::hci::CreateAdvertiserRequest;
-using ::blueberry::facade::hci::CreateAdvertiserResponse;
-using ::blueberry::facade::hci::EnableAdvertiserRequest;
-using ::blueberry::facade::hci::EnablePeriodicAdvertisingRequest;
-using ::blueberry::facade::hci::ExtendedCreateAdvertiserRequest;
-using ::blueberry::facade::hci::ExtendedCreateAdvertiserResponse;
-using ::blueberry::facade::hci::GetNumberOfAdvertisingInstancesResponse;
-using ::blueberry::facade::hci::GetOwnAddressRequest;
-using ::blueberry::facade::hci::LeAdvertisingManagerFacade;
-using ::blueberry::facade::hci::RemoveAdvertiserRequest;
-using ::blueberry::facade::hci::SetDataRequest;
-using ::blueberry::facade::hci::SetParametersRequest;
-using ::blueberry::facade::hci::SetPeriodicDataRequest;
-using ::blueberry::facade::hci::SetPeriodicParametersRequest;
-
-class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Service,
- AdvertisingCallback {
-public:
- LeAdvertisingManagerFacadeService(LeAdvertisingManager* le_advertising_manager,
- os::Handler* facade_handler)
- : le_advertising_manager_(le_advertising_manager), facade_handler_(facade_handler) {
- log::assert_that(le_advertising_manager_ != nullptr,
- "assert failed: le_advertising_manager_ != nullptr");
- log::assert_that(facade_handler_ != nullptr, "assert failed: facade_handler_ != nullptr");
- le_advertising_manager_->RegisterAdvertisingCallback(this);
- }
-
- ::grpc::Status CreateAdvertiser(::grpc::ServerContext* /* context */,
- const CreateAdvertiserRequest* request,
- CreateAdvertiserResponse* response) override {
- hci::AdvertisingConfig config = {};
- if (!AdvertisingConfigFromProto(request->config(), &config)) {
- log::warn("Error parsing advertising config {}", request->SerializeAsString());
- response->set_advertiser_id(LeAdvertisingManager::kInvalidId);
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT,
- "Error while parsing advertising config");
- }
- LeAdvertiser le_advertiser(config);
-
- pending_advertiser_id_ = std::promise<AdvertiserId>();
- auto future = pending_advertiser_id_->get_future();
- le_advertising_manager_->ExtendedCreateAdvertiser(
- kAdvertiserClientIdJni, 0, config,
- common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)),
- common::Bind(&LeAdvertiser::TerminatedCallback, common::Unretained(&le_advertiser)), 0,
- 0, facade_handler_);
-
- auto advertiser_id = future.get();
- if (advertiser_id != LeAdvertisingManager::kInvalidId) {
- le_advertiser.SetAdvertiserId(advertiser_id);
- le_advertisers_.push_back(le_advertiser);
- } else {
- log::warn("Failed to create advertiser");
- }
- response->set_advertiser_id(advertiser_id);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status ExtendedCreateAdvertiser(::grpc::ServerContext* /* context */,
- const ExtendedCreateAdvertiserRequest* request,
- ExtendedCreateAdvertiserResponse* response) override {
- hci::AdvertisingConfig config = {};
- if (!ExtendedAdvertisingConfigFromProto(request->config(), &config)) {
- log::warn("Error parsing advertising config {}", request->SerializeAsString());
- response->set_advertiser_id(LeAdvertisingManager::kInvalidId);
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT,
- "Error while parsing advertising config");
- }
- LeAdvertiser le_advertiser(config);
- pending_advertiser_id_ = std::promise<AdvertiserId>();
- auto future = pending_advertiser_id_->get_future();
- le_advertising_manager_->ExtendedCreateAdvertiser(
- kAdvertiserClientIdJni, 0, config,
- common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)),
- common::Bind(&LeAdvertiser::TerminatedCallback, common::Unretained(&le_advertiser)), 0,
- 0, facade_handler_);
-
- auto advertiser_id = future.get();
- if (advertiser_id != LeAdvertisingManager::kInvalidId) {
- le_advertiser.SetAdvertiserId(advertiser_id);
- le_advertisers_.push_back(le_advertiser);
- } else {
- log::warn("Failed to create advertiser");
- }
- response->set_advertiser_id(advertiser_id);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status EnableAdvertiser(::grpc::ServerContext* /* context */,
- const EnableAdvertiserRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- le_advertising_manager_->EnableAdvertiser(request->advertiser_id(), request->enable(), 0, 0);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetData(::grpc::ServerContext* /* context */, const SetDataRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- std::vector<GapData> advertising_data = {};
- for (const auto& elem : request->data()) {
- advertising_data.push_back(GapDataFromProto(elem));
- }
- le_advertising_manager_->SetData(request->advertiser_id(), request->set_scan_rsp(),
- advertising_data);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetParameters(::grpc::ServerContext* /* context */,
- const SetParametersRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- hci::AdvertisingConfig config = {};
- if (!AdvertisingConfigFromProto(request->config(), &config)) {
- log::warn("Error parsing advertising config {}", request->SerializeAsString());
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT,
- "Error while parsing advertising config");
- }
- le_advertising_manager_->SetParameters(request->advertiser_id(), config);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetPeriodicParameters(::grpc::ServerContext* /* context */,
- const SetPeriodicParametersRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- hci::PeriodicAdvertisingParameters config = {};
- if (!PeriodicAdvertisingParametersFromProto(request->config(), &config)) {
- log::warn("Error parsing periodic advertising parameters {}", request->SerializeAsString());
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT,
- "Error while parsing periodic advertising parameters");
- }
- le_advertising_manager_->SetPeriodicParameters(request->advertiser_id(), config);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetPeriodicData(::grpc::ServerContext* /* context */,
- const SetPeriodicDataRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- std::vector<GapData> advertising_data = {};
- for (const auto& elem : request->data()) {
- advertising_data.push_back(GapDataFromProto(elem));
- }
- le_advertising_manager_->SetPeriodicData(request->advertiser_id(), advertising_data);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status EnablePeriodicAdvertising(::grpc::ServerContext* /* context */,
- const EnablePeriodicAdvertisingRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- le_advertising_manager_->EnablePeriodicAdvertising(request->advertiser_id(), request->enable(),
- request->include_adi());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status GetOwnAddress(::grpc::ServerContext* /* context */,
- const GetOwnAddressRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- le_advertising_manager_->GetOwnAddress(request->advertiser_id());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status GetNumberOfAdvertisingInstances(
- ::grpc::ServerContext* /* context */, const ::google::protobuf::Empty* /* request */,
- GetNumberOfAdvertisingInstancesResponse* response) override {
- response->set_num_advertising_instances(
- le_advertising_manager_->GetNumberOfAdvertisingInstances());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status RemoveAdvertiser(::grpc::ServerContext* /* context */,
- const RemoveAdvertiserRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- if (request->advertiser_id() == LeAdvertisingManager::kInvalidId) {
- log::warn("Invalid advertiser ID {}", request->advertiser_id());
- return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invlid advertiser ID received");
- }
- le_advertising_manager_->RemoveAdvertiser(request->advertiser_id());
- for (auto iter = le_advertisers_.begin(); iter != le_advertisers_.end();) {
- if (iter->GetAdvertiserId() == request->advertiser_id()) {
- iter = le_advertisers_.erase(iter);
- } else {
- ++iter;
- }
- }
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status FetchCallbackEvents(
- ::grpc::ServerContext* context, const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<AdvertisingCallbackMsg>* writer) override {
- return callback_events_.RunLoop(context, writer);
- }
-
- ::grpc::Status FetchAddressEvents(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<AddressMsg>* writer) override {
- return address_events_.RunLoop(context, writer);
- }
-
- void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, int8_t /* tx_power */,
- AdvertisingStatus status) {
- if (pending_advertiser_id_.has_value()) {
- pending_advertiser_id_->set_value(advertiser_id);
- pending_advertiser_id_.reset();
- }
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::ADVERTISING_SET_STARTED);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- msg.set_data(reg_id);
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable, AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::ADVERTISING_ENABLED);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- msg.set_data(enable ? 1 : 0);
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnAdvertisingDataSet(uint8_t advertiser_id, AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::ADVERTISING_DATA_SET);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnScanResponseDataSet(uint8_t advertiser_id, AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::SCAN_RESPONSE_DATA_SET);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t /* tx_power */,
- AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::ADVERTISING_PARAMETERS_UPDATED);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id, AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::PERIODIC_ADVERTISING_PARAMETERS_UPDATED);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::PERIODIC_ADVERTISING_DATA_SET);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool /* enable */,
- AdvertisingStatus status) {
- AdvertisingCallbackMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::PERIODIC_ADVERTISING_ENABLED);
- msg.set_advertiser_id(advertiser_id);
- msg.set_status(static_cast<facade::AdvertisingStatus>(status));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, Address address) {
- log::info("OnOwnAddressRead Address:{}, address_type:{}", address, address_type);
- AddressMsg msg;
- msg.set_message_type(AdvertisingCallbackMsgType::OWN_ADDRESS_READ);
- msg.set_advertiser_id(advertiser_id);
- blueberry::facade::BluetoothAddressWithType facade_address;
- facade_address.mutable_address()->set_address(address.ToString());
- facade_address.set_type(static_cast<facade::BluetoothAddressTypeEnum>(address_type));
- *msg.mutable_address() = facade_address;
- address_events_.OnIncomingEvent(msg);
- }
-
- std::vector<LeAdvertiser> le_advertisers_;
- LeAdvertisingManager* le_advertising_manager_;
- std::optional<std::promise<AdvertiserId>> pending_advertiser_id_;
- os::Handler* facade_handler_;
- ::bluetooth::grpc::GrpcEventQueue<AdvertisingCallbackMsg> callback_events_{"callback events"};
- ::bluetooth::grpc::GrpcEventQueue<AddressMsg> address_events_{"address events"};
-};
-
-void LeAdvertisingManagerFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<hci::LeAdvertisingManager>();
-}
-
-void LeAdvertisingManagerFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new LeAdvertisingManagerFacadeService(GetDependency<hci::LeAdvertisingManager>(),
- GetHandler());
-}
-
-void LeAdvertisingManagerFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* LeAdvertisingManagerFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory LeAdvertisingManagerFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new LeAdvertisingManagerFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_advertising_manager_facade.h b/system/gd/hci/facade/le_advertising_manager_facade.h
deleted file mode 100644
index 99913f9a31..0000000000
--- a/system/gd/hci/facade/le_advertising_manager_facade.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class LeAdvertisingManagerFacadeService;
-
-class LeAdvertisingManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
-
- ::grpc::Service* GetService() const override;
-
-private:
- LeAdvertisingManagerFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_initiator_address_facade.cc b/system/gd/hci/facade/le_initiator_address_facade.cc
deleted file mode 100644
index dcc2da0e35..0000000000
--- a/system/gd/hci/facade/le_initiator_address_facade.cc
+++ /dev/null
@@ -1,131 +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 "hci/facade/le_initiator_address_facade.h"
-
-#include "blueberry/facade/hci/le_initiator_address_facade.grpc.pb.h"
-#include "blueberry/facade/hci/le_initiator_address_facade.pb.h"
-#include "hci/acl_manager.h"
-#include "hci/hci_packets.h"
-#include "hci/octets.h"
-#include "packet/raw_builder.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-using ::bluetooth::packet::RawBuilder;
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using namespace blueberry::facade::hci;
-
-class LeInitiatorAddressFacadeService : public LeInitiatorAddressFacade::Service {
-public:
- LeInitiatorAddressFacadeService(AclManager* acl_manager, ::bluetooth::os::Handler* facade_handler)
- : acl_manager_(acl_manager),
- address_manager_(acl_manager_->GetLeAddressManager()),
- facade_handler_(facade_handler) {
- log::assert_that(facade_handler_ != nullptr, "assert failed: facade_handler_ != nullptr");
- }
-
- ::grpc::Status SetPrivacyPolicyForInitiatorAddress(
- ::grpc::ServerContext* /* context */, const PrivacyPolicy* request,
- ::google::protobuf::Empty* /* writer */) override {
- Address address = Address::kEmpty;
- LeAddressManager::AddressPolicy address_policy =
- static_cast<LeAddressManager::AddressPolicy>(request->address_policy());
- if (address_policy == LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS) {
- log::assert_that(
- Address::FromString(request->address_with_type().address().address(), address),
- "assert failed: "
- "Address::FromString(request->address_with_type().address().address(), "
- "address)");
- }
- AddressWithType address_with_type(
- address, static_cast<AddressType>(request->address_with_type().type()));
- auto minimum_rotation_time = std::chrono::milliseconds(request->minimum_rotation_time());
- auto maximum_rotation_time = std::chrono::milliseconds(request->maximum_rotation_time());
- Octet16 irk = {};
- auto request_irk_length = request->rotation_irk().end() - request->rotation_irk().begin();
- if (request_irk_length == kOctet16Length) {
- std::vector<uint8_t> irk_data(request->rotation_irk().begin(), request->rotation_irk().end());
- std::copy_n(irk_data.begin(), kOctet16Length, irk.begin());
- acl_manager_->SetPrivacyPolicyForInitiatorAddressForTest(
- address_policy, address_with_type, irk, minimum_rotation_time, maximum_rotation_time);
- } else {
- acl_manager_->SetPrivacyPolicyForInitiatorAddress(
- address_policy, address_with_type, minimum_rotation_time, maximum_rotation_time);
- log::assert_that(request_irk_length == 0, "assert failed: request_irk_length == 0");
- }
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status GetCurrentInitiatorAddress(
- ::grpc::ServerContext* /* context */, const ::google::protobuf::Empty* /* request */,
- ::blueberry::facade::BluetoothAddressWithType* response) override {
- AddressWithType current = address_manager_->GetInitiatorAddress();
- auto bluetooth_address = new ::blueberry::facade::BluetoothAddress();
- bluetooth_address->set_address(current.GetAddress().ToString());
- response->set_type(
- static_cast<::blueberry::facade::BluetoothAddressTypeEnum>(current.GetAddressType()));
- response->set_allocated_address(bluetooth_address);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status NewResolvableAddress(
- ::grpc::ServerContext* /* context */, const ::google::protobuf::Empty* /* request */,
- ::blueberry::facade::BluetoothAddressWithType* response) override {
- AddressWithType another = address_manager_->NewResolvableAddress();
- auto bluetooth_address = new ::blueberry::facade::BluetoothAddress();
- bluetooth_address->set_address(another.GetAddress().ToString());
- response->set_type(
- static_cast<::blueberry::facade::BluetoothAddressTypeEnum>(another.GetAddressType()));
- response->set_allocated_address(bluetooth_address);
- return ::grpc::Status::OK;
- }
-
-private:
- AclManager* acl_manager_;
- LeAddressManager* address_manager_;
- ::bluetooth::os::Handler* facade_handler_;
-};
-
-void LeInitiatorAddressFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<AclManager>();
-}
-
-void LeInitiatorAddressFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new LeInitiatorAddressFacadeService(GetDependency<AclManager>(), GetHandler());
-}
-
-void LeInitiatorAddressFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* LeInitiatorAddressFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory LeInitiatorAddressFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new LeInitiatorAddressFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_initiator_address_facade.h b/system/gd/hci/facade/le_initiator_address_facade.h
deleted file mode 100644
index 3952b14146..0000000000
--- a/system/gd/hci/facade/le_initiator_address_facade.h
+++ /dev/null
@@ -1,45 +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.
- */
-
-#pragma once
-
-#include <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-#include "hci/acl_manager.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class LeInitiatorAddressFacadeService;
-
-class LeInitiatorAddressFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- LeInitiatorAddressFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_scanning_manager_facade.cc b/system/gd/hci/facade/le_scanning_manager_facade.cc
deleted file mode 100644
index 243b46ff4e..0000000000
--- a/system/gd/hci/facade/le_scanning_manager_facade.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2019 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 "hci/facade/le_scanning_manager_facade.h"
-
-#include <bluetooth/log.h>
-
-#include <cstdint>
-#include <unordered_map>
-#include <utility>
-
-#include "blueberry/facade/hci/le_scanning_manager_facade.grpc.pb.h"
-#include "blueberry/facade/hci/le_scanning_manager_facade.pb.h"
-#include "common/bidi_queue.h"
-#include "common/bind.h"
-#include "grpc/grpc_event_queue.h"
-#include "hci/le_scanning_manager.h"
-#include "packet/raw_builder.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-using ::grpc::ServerWriter;
-using ::grpc::Status;
-
-using namespace blueberry::facade::hci;
-
-class LeScanningManagerFacadeService : public LeScanningManagerFacade::Service, ScanningCallback {
-public:
- LeScanningManagerFacadeService(LeScanningManager* le_scanning_manager,
- os::Handler* facade_handler)
- : le_scanning_manager_(le_scanning_manager), facade_handler_(facade_handler) {
- log::assert_that(le_scanning_manager_ != nullptr,
- "assert failed: le_scanning_manager_ != nullptr");
- log::assert_that(facade_handler_ != nullptr, "assert failed: facade_handler_ != nullptr");
- le_scanning_manager_->RegisterScanningCallback(this);
- }
-
- ::grpc::Status RegisterScanner(::grpc::ServerContext* /* context */,
- const RegisterScannerRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- uint32_t uuid_raw = request->uuid();
- bluetooth::hci::Uuid uuid = bluetooth::hci::Uuid::From32Bit(uuid_raw);
- le_scanning_manager_->RegisterScanner(uuid);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status Unregister(::grpc::ServerContext* /* context */, const UnregisterRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- le_scanning_manager_->Unregister(request->scanner_id());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status Scan(::grpc::ServerContext* /* context */, const ScanRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- le_scanning_manager_->Scan(request->start());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetScanParameters(::grpc::ServerContext* /* context */,
- const SetScanParametersRequest* request,
- ::google::protobuf::Empty* /* response */) override {
- auto scan_type = static_cast<hci::LeScanType>(request->scan_type());
- le_scanning_manager_->SetScanParameters(request->scanner_id(), scan_type,
- request->scan_interval(), request->scan_window(),
- request->scan_phy());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status FetchCallbackEvents(::grpc::ServerContext* context,
- const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<ScanningCallbackMsg>* writer) override {
- return callback_events_.RunLoop(context, writer);
- }
-
- ::grpc::Status FetchAdvertisingReports(
- ::grpc::ServerContext* context, const ::google::protobuf::Empty* /* request */,
- ::grpc::ServerWriter<AdvertisingReportMsg>* writer) override {
- return advertising_reports_.RunLoop(context, writer);
- }
-
- void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid, ScannerId /* scanner_id */,
- ScanningStatus status) {
- ScanningCallbackMsg msg;
- msg.set_message_type(ScanningCallbackMsgType::SCANNER_REGISTERED);
- msg.set_status(static_cast<facade::ScanningStatus>(status));
- msg.set_data(app_uuid.As32Bit());
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnSetScannerParameterComplete(ScannerId scanner_id, ScanningStatus status) {
- ScanningCallbackMsg msg;
- msg.set_message_type(ScanningCallbackMsgType::SET_SCANNER_PARAMETER_COMPLETE);
- msg.set_status(static_cast<facade::ScanningStatus>(status));
- msg.set_data(static_cast<uint32_t>(scanner_id));
- callback_events_.OnIncomingEvent(msg);
- }
-
- void OnScanResult(uint16_t /* event_type */, uint8_t address_type, Address address,
- uint8_t /* primary_phy */, uint8_t /* secondary_phy */,
- uint8_t /* advertising_sid */, int8_t /* tx_power */, int8_t rssi,
- uint16_t /* periodic_advertising_interval */,
- std::vector<uint8_t> advertising_data) {
- AdvertisingReportMsg advertising_report_msg;
- std::vector<LeExtendedAdvertisingResponseRaw> advertisements;
- LeExtendedAdvertisingResponseRaw le_extended_advertising_report;
- le_extended_advertising_report.address_type_ = (DirectAdvertisingAddressType)address_type;
- le_extended_advertising_report.address_ = address;
- le_extended_advertising_report.advertising_data_ = advertising_data;
- le_extended_advertising_report.rssi_ = rssi;
- advertisements.push_back(le_extended_advertising_report);
-
- auto builder = LeExtendedAdvertisingReportRawBuilder::Create(advertisements);
- std::vector<uint8_t> bytes;
- BitInserter bit_inserter(bytes);
- builder->Serialize(bit_inserter);
- advertising_report_msg.set_event(std::string(bytes.begin(), bytes.end()));
- advertising_reports_.OnIncomingEvent(std::move(advertising_report_msg));
- }
- void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo /* on_found_on_lost_info */){};
- void OnBatchScanReports(int /* client_if */, int /* status */, int /* report_format */,
- int /* num_records */, std::vector<uint8_t> /* data */) {}
- void OnBatchScanThresholdCrossed(int /* client_if */) {}
- void OnTimeout() {}
- void OnFilterEnable(Enable /* enable */, uint8_t /* status */) {}
- void OnFilterParamSetup(uint8_t /* available_spaces */, ApcfAction /* action */,
- uint8_t /* status */) {}
- void OnFilterConfigCallback(ApcfFilterType /* filter_type */, uint8_t /* available_spaces */,
- ApcfAction /* action */, uint8_t /* status */) {}
-
- void OnPeriodicSyncStarted(int /* reg_id */, uint8_t /* status */, uint16_t /* sync_handle */,
- uint8_t /* advertising_sid */, AddressWithType /* address_with_type */,
- uint8_t /* phy */, uint16_t /* interval */) override {
- log::info("OnPeriodicSyncStarted in LeScanningManagerFacadeService");
- }
-
- void OnPeriodicSyncReport(uint16_t /* sync_handle */, int8_t /* tx_power */, int8_t /* rssi */,
- uint8_t /* status */, std::vector<uint8_t> /* data */) override {
- log::info("OnPeriodicSyncReport in LeScanningManagerFacadeService");
- }
-
- void OnPeriodicSyncLost(uint16_t /* sync_handle */) override {
- log::info("OnPeriodicSyncLost in LeScanningManagerFacadeService");
- }
-
- void OnPeriodicSyncTransferred(int /* pa_source */, uint8_t /* status */,
- Address /* address */) override {
- log::info("OnPeriodicSyncTransferred in LeScanningManagerFacadeService");
- }
-
- void OnBigInfoReport(uint16_t /* sync_handle */, bool /* encrypted */) override {
- log::info("OnBigInfoReport in LeScanningManagerFacadeService");
- }
-
- LeScanningManager* le_scanning_manager_;
- os::Handler* facade_handler_;
- ::bluetooth::grpc::GrpcEventQueue<AdvertisingReportMsg> advertising_reports_{
- "advertising reports"};
- ::bluetooth::grpc::GrpcEventQueue<ScanningCallbackMsg> callback_events_{"callback events"};
-};
-
-void LeScanningManagerFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<hci::LeScanningManager>();
-}
-
-void LeScanningManagerFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ =
- new LeScanningManagerFacadeService(GetDependency<hci::LeScanningManager>(), GetHandler());
-}
-
-void LeScanningManagerFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* LeScanningManagerFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory LeScanningManagerFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new LeScanningManagerFacadeModule(); });
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/facade/le_scanning_manager_facade.h b/system/gd/hci/facade/le_scanning_manager_facade.h
deleted file mode 100644
index a3e68315d8..0000000000
--- a/system/gd/hci/facade/le_scanning_manager_facade.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-
-namespace bluetooth {
-namespace hci {
-namespace facade {
-
-class LeScanningManagerFacadeService;
-
-class LeScanningManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
-
- ::grpc::Service* GetService() const override;
-
-private:
- LeScanningManagerFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace hci
-} // namespace bluetooth
diff --git a/system/gd/hci/le_address_manager.cc b/system/gd/hci/le_address_manager.cc
index 256276e95f..bddbcaf4d1 100644
--- a/system/gd/hci/le_address_manager.cc
+++ b/system/gd/hci/le_address_manager.cc
@@ -157,13 +157,11 @@ void LeAddressManager::SetPrivacyPolicyForInitiatorAddress(
log::info("minimum_rotation_time_={}ms, maximum_rotation_time_={}ms",
minimum_rotation_time_.count(), maximum_rotation_time_.count());
}
- if (com::android::bluetooth::flags::rpa_offload_to_bt_controller() &&
- controller_->IsSupported(hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2)) {
+ if (controller_->IsRpaGenerationSupported()) {
auto min_seconds = std::chrono::duration_cast<std::chrono::seconds>(minimum_rotation_time_);
auto max_seconds = std::chrono::duration_cast<std::chrono::seconds>(maximum_rotation_time_);
- log::info(
- "Support RPA offload, set min_seconds={}s, max_seconds={}s",
- min_seconds.count(), max_seconds.count());
+ log::info("Support RPA offload, set min_seconds={}s, max_seconds={}s", min_seconds.count(),
+ max_seconds.count());
/* Default to 7 minutes minimum, 15 minutes maximum for random address refreshing;
* device can override. */
auto packet = hci::LeSetResolvablePrivateAddressTimeoutV2Builder::Create(
@@ -223,13 +221,11 @@ void LeAddressManager::SetPrivacyPolicyForInitiatorAddressForTest(
maximum_rotation_time_ = maximum_rotation_time;
log::info("minimum_rotation_time_={}ms, maximum_rotation_time_={}ms",
minimum_rotation_time_.count(), maximum_rotation_time_.count());
- if (com::android::bluetooth::flags::rpa_offload_to_bt_controller() &&
- controller_->IsSupported(hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2)) {
+ if (controller_->IsRpaGenerationSupported()) {
auto min_seconds = std::chrono::duration_cast<std::chrono::seconds>(minimum_rotation_time_);
auto max_seconds = std::chrono::duration_cast<std::chrono::seconds>(maximum_rotation_time_);
- log::info(
- "Support RPA offload, set min_seconds={}s, max_seconds={}s",
- min_seconds.count(), max_seconds.count());
+ log::info("Support RPA offload, set min_seconds={}s, max_seconds={}s", min_seconds.count(),
+ max_seconds.count());
/* Default to 7 minutes minimum, 15 minutes maximum for random address refreshing;
* device can override. */
auto packet = hci::LeSetResolvablePrivateAddressTimeoutV2Builder::Create(
@@ -269,8 +265,7 @@ void LeAddressManager::register_client(LeAddressManagerCallback* callback) {
} else if (address_policy_ == AddressPolicy::USE_RESOLVABLE_ADDRESS ||
address_policy_ == AddressPolicy::USE_NON_RESOLVABLE_ADDRESS) {
if (registered_clients_.size() == 1) {
- if (!com::android::bluetooth::flags::rpa_offload_to_bt_controller() ||
- !controller_->IsSupported(hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2)) {
+ if (!controller_->IsRpaGenerationSupported()) {
schedule_rotate_random_address();
log::info("Scheduled address rotation for first client registered");
}
diff --git a/system/gd/hci/le_address_manager_test.cc b/system/gd/hci/le_address_manager_test.cc
index 7e5c679ff1..33efcb51a2 100644
--- a/system/gd/hci/le_address_manager_test.cc
+++ b/system/gd/hci/le_address_manager_test.cc
@@ -18,9 +18,9 @@
#include <gtest/gtest.h>
+#include "hci/controller.h"
#include "hci/hci_layer_fake.h"
#include "hci/octets.h"
-#include "hci/controller.h"
#include "packet/raw_builder.h"
using ::bluetooth::hci::Octet16;
diff --git a/system/gd/hci/le_advertising_manager.cc b/system/gd/hci/le_advertising_manager.cc
index e40b253f6a..5213569243 100644
--- a/system/gd/hci/le_advertising_manager.cc
+++ b/system/gd/hci/le_advertising_manager.cc
@@ -658,9 +658,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
// but we only rotate if the AdvertiserAddressType is non-public
// or non-rpa requested by leaudio(since static random addresses don't rotate)
if (advertising_sets_[id].address_type != AdvertiserAddressType::PUBLIC &&
- !leaudio_requested_nrpa &&
- (!com::android::bluetooth::flags::rpa_offload_to_bt_controller() ||
- !controller_->IsSupported(hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2))) {
+ !leaudio_requested_nrpa && (!controller_->IsRpaGenerationSupported())) {
// start timer for random address
log::info("Scheduling address rotation for advertiser_id={}", id);
if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) {
@@ -906,8 +904,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
auto own_address_type = static_cast<OwnAddressType>(
advertising_sets_[advertiser_id].current_address.GetAddressType());
- if (com::android::bluetooth::flags::rpa_offload_to_bt_controller() &&
- controller_->IsSupported(hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2) &&
+ if (controller_->IsRpaGenerationSupported() &&
own_address_type != OwnAddressType::PUBLIC_DEVICE_ADDRESS) {
log::info("Support RPA offload, set own address type RESOLVABLE_OR_RANDOM_ADDRESS");
own_address_type = OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS;
@@ -1142,11 +1139,9 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
data_len += data[i].size();
}
- int maxDataLength =
- (com::android::bluetooth::flags::ble_check_data_length_on_legacy_advertising() &&
- advertising_sets_[advertiser_id].is_legacy)
- ? kLeMaximumLegacyAdvertisingDataLength
- : le_maximum_advertising_data_length_;
+ int maxDataLength = advertising_sets_[advertiser_id].is_legacy
+ ? kLeMaximumLegacyAdvertisingDataLength
+ : le_maximum_advertising_data_length_;
if (data_len > maxDataLength) {
log::warn("advertising data len {} exceeds maxDataLength {}", data_len, maxDataLength);
diff --git a/system/gd/hci/le_scanning_manager.cc b/system/gd/hci/le_scanning_manager.cc
index 5934cf7047..bba3815048 100644
--- a/system/gd/hci/le_scanning_manager.cc
+++ b/system/gd/hci/le_scanning_manager.cc
@@ -466,8 +466,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback {
stop_scan();
if (le_address_manager_->GetAddressPolicy() != LeAddressManager::USE_PUBLIC_ADDRESS) {
- if (com::android::bluetooth::flags::rpa_offload_to_bt_controller() &&
- controller_->IsSupported(hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_V2)) {
+ if (controller_->IsRpaGenerationSupported()) {
log::info("Support RPA offload, set own address type RESOLVABLE_OR_RANDOM_ADDRESS");
own_address_type_ = OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS;
} else {
@@ -1578,8 +1577,14 @@ struct LeScanningManager::impl : public LeAddressManagerCallback {
return;
}
paused_ = false;
- if (scan_on_resume_ == true) {
+ if (scan_on_resume_) {
scan_on_resume_ = false;
+ if (com::android::bluetooth::flags::configure_scan_on_resume()) {
+ // This is a workaround for b/381010390.
+ // We'll eventually recover scan parameters which could be overridden by
+ // btm_send_hci_set_scan_params.
+ configure_scan();
+ }
start_scan();
}
le_address_manager_->AckResume(this);
diff --git a/system/gd/hci/le_scanning_manager_test.cc b/system/gd/hci/le_scanning_manager_test.cc
index 4176e857b8..44269651ce 100644
--- a/system/gd/hci/le_scanning_manager_test.cc
+++ b/system/gd/hci/le_scanning_manager_test.cc
@@ -828,6 +828,11 @@ TEST_F(LeScanningManagerExtendedTest, on_pause_on_resume_test) {
// Ensure scan is resumed (enabled)
test_le_address_manager->client_->OnResume();
+ if (com::android::bluetooth::flags::configure_scan_on_resume()) {
+ ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+ test_hci_layer_->IncomingEvent(
+ LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+ }
ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
test_hci_layer_->IncomingEvent(
LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
diff --git a/system/gd/shim/Android.bp b/system/gd/lpp/Android.bp
index c2b1d8b68e..2be7b85d9e 100644
--- a/system/gd/shim/Android.bp
+++ b/system/gd/lpp/Android.bp
@@ -8,15 +8,8 @@ package {
}
filegroup {
- name: "BluetoothShimSources",
+ name: "BluetoothLppOffloadSources",
srcs: [
- "dumpsys.cc",
- ],
-}
-
-filegroup {
- name: "BluetoothShimTestSources",
- srcs: [
- "dumpsys_test.cc",
+ "lpp_offload_manager.cc",
],
}
diff --git a/system/gd/shim/BUILD.gn b/system/gd/lpp/BUILD.gn
index d30e609c2f..b773001ce8 100644
--- a/system/gd/shim/BUILD.gn
+++ b/system/gd/lpp/BUILD.gn
@@ -1,5 +1,5 @@
#
-# Copyright 2021 Google, Inc.
+# Copyright 2024 Google, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,20 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-source_set("BluetoothShimSources") {
+source_set("BluetoothLppOffloadSources") {
sources = [
- "dumpsys.cc",
+ "lpp_offload_manager.cc",
]
+ include_dirs = [ "//bt/system/gd" ]
+
deps = [
- "//bt/flags:bluetooth_flags_c_lib",
- "//bt/system/gd/dumpsys:libbluetooth-dumpsys",
- "//bt/system/gd/dumpsys/bundler:BluetoothGeneratedBundlerSchema_h_bfbs",
- "//bt/system/pdl:BluetoothGeneratedPackets_h",
+ "//bt/system/gd:gd_default_deps",
]
configs += [
- "//bt/system/gd:gd_defaults",
- "//bt/system:external_flatbuffers",
+ "//bt/system:target_defaults",
+ "//bt/system/log:log_defaults",
]
}
diff --git a/system/gd/lpp/lpp_offload_interface.h b/system/gd/lpp/lpp_offload_interface.h
new file mode 100644
index 0000000000..388466f2e5
--- /dev/null
+++ b/system/gd/lpp/lpp_offload_interface.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "hal/socket_hal.h"
+
+namespace bluetooth::lpp {
+
+/**
+ * Interface to low-power processors (LPPs) for supporting LPP offload features.
+ *
+ * This interface allows inheritance from multiple offload HAL interfaces, enabling a unified
+ * offload function management approach through a single interface accessible from the upper layer.
+ */
+class LppOffloadInterface {
+public:
+ LppOffloadInterface() = default;
+
+ virtual ~LppOffloadInterface() = default;
+
+ LppOffloadInterface(const LppOffloadInterface&) = delete;
+
+ LppOffloadInterface& operator=(const LppOffloadInterface&) = delete;
+
+ /**
+ * Registers a socket hal callback function to receive asynchronous events from socket HAL.
+ *
+ * The provided callback function must be executed on the main thread.
+ *
+ * @param callback A pointer to the callback function. Must not be nullptr and must have static
+ * lifetime.
+ * @return True if the callback was successfully registered, false otherwise.
+ */
+ virtual bool RegisterSocketHalCallback(hal::SocketHalCallback* callbacks) = 0;
+
+ /**
+ * Retrieves the supported offload socket capabilities.
+ *
+ * @return Supported socket capabilities
+ */
+ virtual hal::SocketCapabilities GetSocketCapabilities() const = 0;
+
+ /**
+ * Notifies the socket HAL that the socket has been opened.
+ *
+ * If this method returns true, SocketHalCallback.SocketOpenedComplete() shall be called to
+ * indicate the result of this operation.
+ *
+ * @param context Socket context including socket ID, channel, hub, and endpoint info
+ * @return True if calling this method was successful, false otherwise
+ */
+ virtual bool SocketOpened(const hal::SocketContext& context) = 0;
+
+ /**
+ * Notifies the socket HAL that the socket has been closed.
+ *
+ * @param socket_id Identifier assigned to the socket by the host stack
+ */
+ virtual void SocketClosed(uint64_t socket_id) = 0;
+};
+
+} // namespace bluetooth::lpp
diff --git a/system/gd/facade/grpc_root_server.h b/system/gd/lpp/lpp_offload_interface_mock.h
index 062ddcf150..03cd5f4f52 100644
--- a/system/gd/facade/grpc_root_server.h
+++ b/system/gd/lpp/lpp_offload_interface_mock.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,32 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
-#include <grpc++/grpc++.h>
+#include <gmock/gmock.h>
-#include <memory>
-#include <string>
+#include "lpp/lpp_offload_interface.h"
-namespace bluetooth {
-namespace facade {
+// Unit test interfaces
+namespace bluetooth::lpp::testing {
-class GrpcRootServer {
+class MockLppOffloadInterface : public LppOffloadInterface {
public:
- GrpcRootServer();
- ~GrpcRootServer();
-
- void StartServer(const std::string& address, int grpc_root_server_port, int grpc_port);
-
- void StopServer();
-
- void RunGrpcLoop();
-
-private:
- struct impl;
- std::unique_ptr<impl> pimpl_;
+ MOCK_METHOD(bool, RegisterSocketHalCallback, (hal::SocketHalCallback*), (override));
+ MOCK_METHOD(hal::SocketCapabilities, GetSocketCapabilities, (), (const override));
+ MOCK_METHOD(bool, SocketOpened, (const hal::SocketContext&), (override));
+ MOCK_METHOD(void, SocketClosed, (uint64_t), (override));
};
-} // namespace facade
-} // namespace bluetooth
+} // namespace bluetooth::lpp::testing
diff --git a/system/gd/lpp/lpp_offload_manager.cc b/system/gd/lpp/lpp_offload_manager.cc
new file mode 100644
index 0000000000..c5c1fb247e
--- /dev/null
+++ b/system/gd/lpp/lpp_offload_manager.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "lpp_offload_manager.h"
+
+#include <bluetooth/log.h>
+
+#include <string>
+
+#include "hal/socket_hal.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/system_properties.h"
+
+namespace bluetooth::lpp {
+
+const ModuleFactory LppOffloadManager::Factory =
+ ModuleFactory([]() { return new LppOffloadManager(); });
+
+struct LppOffloadManager::impl {
+ ~impl() {}
+
+ void start(os::Handler* handler, hal::SocketHal* socket_hal) {
+ log::info("");
+ handler_ = handler;
+ socket_hal_ = socket_hal;
+ socket_capabilities_ = socket_hal_->GetSocketCapabilities();
+ }
+
+ void stop() {
+ log::info("");
+ socket_capabilities_ = {};
+ }
+
+ bool register_socket_hal_callbacks(hal::SocketHalCallback* callbacks) {
+ log::info("");
+ return socket_hal_->RegisterCallback(callbacks);
+ }
+
+ hal::SocketCapabilities get_socket_capabilities() const {
+ log::info("");
+ return socket_capabilities_;
+ }
+
+ bool socket_opened(const hal::SocketContext& context) {
+ log::info("socket_id: {}", context.socket_id);
+ return socket_hal_->Opened(context);
+ }
+
+ void socket_closed(uint64_t socket_id) {
+ log::info("socket_id: {}", socket_id);
+ return socket_hal_->Closed(socket_id);
+ }
+
+ os::Handler* handler_;
+ hal::SocketHal* socket_hal_;
+ hal::SocketCapabilities socket_capabilities_;
+};
+
+LppOffloadManager::LppOffloadManager() { pimpl_ = std::make_unique<impl>(); }
+
+LppOffloadManager::~LppOffloadManager() = default;
+
+void LppOffloadManager::ListDependencies(ModuleList* list) const { list->add<hal::SocketHal>(); }
+
+void LppOffloadManager::Start() { pimpl_->start(GetHandler(), GetDependency<hal::SocketHal>()); }
+
+void LppOffloadManager::Stop() { pimpl_->stop(); }
+
+std::string LppOffloadManager::ToString() const { return "Low Power Processor Offload Manager"; }
+
+bool LppOffloadManager::RegisterSocketHalCallback(hal::SocketHalCallback* callbacks) {
+ return pimpl_->register_socket_hal_callbacks(callbacks);
+}
+
+hal::SocketCapabilities LppOffloadManager::GetSocketCapabilities() const {
+ return pimpl_->get_socket_capabilities();
+}
+
+bool LppOffloadManager::SocketOpened(const hal::SocketContext& context) {
+ return pimpl_->socket_opened(context);
+}
+
+void LppOffloadManager::SocketClosed(uint64_t socket_id) {
+ CallOn(pimpl_.get(), &impl::socket_closed, socket_id);
+}
+
+} // namespace bluetooth::lpp
diff --git a/system/gd/lpp/lpp_offload_manager.h b/system/gd/lpp/lpp_offload_manager.h
new file mode 100644
index 0000000000..90097f77bd
--- /dev/null
+++ b/system/gd/lpp/lpp_offload_manager.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <bluetooth/log.h>
+
+#include <memory>
+#include <string>
+
+#include "lpp_offload_interface.h"
+#include "module.h"
+
+namespace bluetooth::lpp {
+
+class LppOffloadManager : public bluetooth::Module, public LppOffloadInterface {
+public:
+ LppOffloadManager();
+
+ LppOffloadManager(const LppOffloadManager&) = delete;
+
+ LppOffloadManager& operator=(const LppOffloadManager&) = delete;
+
+ ~LppOffloadManager();
+
+ bool RegisterSocketHalCallback(hal::SocketHalCallback* callbacks) override;
+
+ hal::SocketCapabilities GetSocketCapabilities() const override;
+
+ bool SocketOpened(const hal::SocketContext& context) override;
+
+ void SocketClosed(uint64_t socket_id) override;
+
+ static const ModuleFactory Factory;
+
+protected:
+ void ListDependencies(ModuleList* list) const override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+};
+
+} // namespace bluetooth::lpp
diff --git a/system/gd/metrics/bluetooth_event.h b/system/gd/metrics/bluetooth_event.h
index 89fc1384a5..acdb7a84f6 100644
--- a/system/gd/metrics/bluetooth_event.h
+++ b/system/gd/metrics/bluetooth_event.h
@@ -19,6 +19,7 @@
#include "bta/include/bta_sec_api.h"
#include "hci/address.h"
#include "hci/hci_packets.h"
+#include "os/metrics.h"
#include "stack/include/btm_status.h"
#include "stack/include/hci_error_code.h"
#include "types/raw_address.h"
@@ -47,5 +48,7 @@ void LogSDPComplete(const RawAddress& raw_address, tBTA_STATUS status);
void LogLePairingFail(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing);
+android::bluetooth::State MapErrorCodeToState(hci::ErrorCode reason);
+
} // namespace metrics
} // namespace bluetooth
diff --git a/system/gd/metrics/chromeos/metrics_event.cc b/system/gd/metrics/chromeos/metrics_event.cc
index 806db26bfe..3715dcec71 100644
--- a/system/gd/metrics/chromeos/metrics_event.cc
+++ b/system/gd/metrics/chromeos/metrics_event.cc
@@ -21,7 +21,6 @@
#include <base/strings/pattern.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
#include <map>
#include <utility>
@@ -42,8 +41,8 @@ namespace {
// these consts path below are for getting the chipset info
constexpr char kChipsetInfoWlanDirPath[] = "/sys/class/net/wlan0/device";
constexpr char kChipsetInfoMlanDirPath[] = "/sys/class/net/mlan0/device";
-constexpr char kChipsetInfoModaliasPath[] = "/sys/class/bluetooth/hci%d/device/modalias";
-constexpr char kChipInfoModuleDirPath[] = "/sys/class/bluetooth/hci%d/device/driver/module";
+constexpr char kChipsetInfoModaliasPath[] = "/sys/class/bluetooth/hci{}/device/modalias";
+constexpr char kChipInfoModuleDirPath[] = "/sys/class/bluetooth/hci{}/device/driver/module";
} // namespace
// topshim::btif::BtBondState is a copy of hardware/bluetooth.h:bt_bond_state_t
@@ -676,7 +675,7 @@ static int64_t GetChipsetInfoId(const char* path, const char* file) {
static std::string GetChipsetInfoModuleName() {
std::string module;
int adapter_index = GetAdapterIndex();
- std::string path = base::StringPrintf(kChipsetInfoModaliasPath, adapter_index);
+ std::string path = std::format(kChipsetInfoModaliasPath, adapter_index);
if (base::ReadFileToString(base::FilePath(path), &module)) {
return base::CollapseWhitespaceASCII(module, false);
@@ -689,7 +688,7 @@ static MetricTransportType GetChipsetInfoTransport(void) {
base::FilePath module_realpath;
std::string module_name;
int adapter_index = GetAdapterIndex();
- std::string path = base::StringPrintf(kChipInfoModuleDirPath, adapter_index);
+ std::string path = std::format(kChipInfoModuleDirPath, adapter_index);
// examples of module_realpath: /sys/module/btusb and /sys/module/hci_uart
module_realpath = base::MakeAbsoluteFilePath(base::FilePath(path));
diff --git a/system/gd/module.cc b/system/gd/module.cc
index 5a2cdf142c..97f6132f31 100644
--- a/system/gd/module.cc
+++ b/system/gd/module.cc
@@ -45,13 +45,6 @@ Module* Module::GetDependency(const ModuleFactory* module) const {
log::fatal("Module was not listed as a dependency in ListDependencies");
}
-bluetooth::DumpsysDataFinisher EmptyDumpsysDataFinisher =
- [](bluetooth::DumpsysDataBuilder* /* dumpsys_data_builder */) {};
-
-DumpsysDataFinisher Module::GetDumpsysData(flatbuffers::FlatBufferBuilder* /* builder */) const {
- return EmptyDumpsysDataFinisher;
-}
-
Module* ModuleRegistry::Get(const ModuleFactory* module) const {
auto instance = started_modules_.find(module);
log::assert_that(instance != started_modules_.end(),
diff --git a/system/gd/module.h b/system/gd/module.h
index 44aa0bcb29..e708035a77 100644
--- a/system/gd/module.h
+++ b/system/gd/module.h
@@ -17,7 +17,6 @@
#pragma once
#include <bluetooth/log.h>
-#include <flatbuffers/flatbuffers.h>
#include <chrono>
#include <functional>
@@ -33,9 +32,11 @@
#include "os/thread.h"
namespace bluetooth {
+namespace shim {
+class Stack;
+} // namespace shim
class Module;
-class ModuleDumper;
class ModuleRegistry;
class TestModuleRegistry;
class FuzzTestModuleRegistry;
@@ -68,11 +69,6 @@ private:
std::vector<const ModuleFactory*> list_;
};
-struct DumpsysDataBuilder;
-using DumpsysDataFinisher = std::function<void(DumpsysDataBuilder*)>;
-
-extern DumpsysDataFinisher EmptyDumpsysDataFinisher;
-
// Each leaf node module must have a factory like so:
//
// static const ModuleFactory Factory;
@@ -81,7 +77,6 @@ extern DumpsysDataFinisher EmptyDumpsysDataFinisher;
// The module registry will also use the factory as the identifier
// for that module.
class Module {
- friend ModuleDumper;
friend ModuleRegistry;
friend TestModuleRegistry;
@@ -120,8 +115,6 @@ protected:
GetHandler()->CallOn(obj, std::forward<Functor>(functor), std::forward<Args>(args)...);
}
- virtual DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const;
-
private:
Module* GetDependency(const ModuleFactory* module) const;
@@ -132,8 +125,7 @@ private:
class ModuleRegistry {
friend Module;
- friend ModuleDumper;
- friend class StackManager;
+ friend shim::Stack;
public:
template <class T>
diff --git a/system/gd/module_dumper.cc b/system/gd/module_dumper.cc
deleted file mode 100644
index 23bb6aa8f2..0000000000
--- a/system/gd/module_dumper.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2023 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 "BtGdModule"
-
-#include "module_dumper.h"
-
-#include <sstream>
-
-#include "dumpsys_data_generated.h"
-#include "module.h"
-#include "os/wakelock_manager.h"
-
-using ::bluetooth::os::WakelockManager;
-
-namespace bluetooth {
-
-void ModuleDumper::DumpState(std::string* output, std::ostringstream& /*oss*/) const {
- log::assert_that(output != nullptr, "assert failed: output != nullptr");
-
- flatbuffers::FlatBufferBuilder builder(1024);
- auto title = builder.CreateString(title_);
-
- auto wakelock_offset = WakelockManager::Get().GetDumpsysData(&builder);
-
- std::queue<DumpsysDataFinisher> queue;
- for (auto it = module_registry_.start_order_.rbegin(); it != module_registry_.start_order_.rend();
- it++) {
- auto instance = module_registry_.started_modules_.find(*it);
- log::assert_that(instance != module_registry_.started_modules_.end(),
- "assert failed: instance != module_registry_.started_modules_.end()");
- log::verbose("Starting dumpsys module:{}", instance->second->ToString());
- queue.push(instance->second->GetDumpsysData(&builder));
- log::verbose("Finished dumpsys module:{}", instance->second->ToString());
- }
-
- DumpsysDataBuilder data_builder(builder);
- data_builder.add_title(title);
- data_builder.add_wakelock_manager_data(wakelock_offset);
-
- while (!queue.empty()) {
- queue.front()(&data_builder);
- queue.pop();
- }
-
- builder.Finish(data_builder.Finish());
- *output = std::string(builder.GetBufferPointer(), builder.GetBufferPointer() + builder.GetSize());
-}
-
-} // namespace bluetooth
diff --git a/system/gd/module_dumper.h b/system/gd/module_dumper.h
deleted file mode 100644
index d1953a224d..0000000000
--- a/system/gd/module_dumper.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2019 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 <sstream>
-#include <string>
-
-#include "module.h"
-
-namespace bluetooth {
-
-class ModuleRegistry;
-
-class ModuleDumper {
-public:
- ModuleDumper(int /*fd*/, const ModuleRegistry& module_registry, const char* title)
- : module_registry_(module_registry), title_(title) {}
- void DumpState(std::string* output, std::ostringstream& oss) const;
-
-private:
- const ModuleRegistry& module_registry_;
- const std::string title_;
-};
-
-} // namespace bluetooth
diff --git a/system/gd/module_dumper_flatbuffer.h b/system/gd/module_dumper_flatbuffer.h
deleted file mode 100644
index 21b19a7291..0000000000
--- a/system/gd/module_dumper_flatbuffer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2023 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 <functional>
-
-namespace bluetooth {
-
-struct DumpsysDataBuilder;
-using DumpsysDataFinisher = std::function<void(DumpsysDataBuilder* dumpsys_data_builder)>;
-
-extern DumpsysDataFinisher EmptyDumpsysDataFinisher;
-
-} // namespace bluetooth
diff --git a/system/gd/module_unittest.cc b/system/gd/module_unittest.cc
index 123cd3e469..24ccc8b3d2 100644
--- a/system/gd/module_unittest.cc
+++ b/system/gd/module_unittest.cc
@@ -22,10 +22,7 @@
#include <sstream>
#include <string>
-#include "dumpsys_data_generated.h"
#include "gtest/gtest.h"
-#include "module_dumper.h"
-#include "module_unittest_generated.h"
#include "os/handler.h"
#include "os/thread.h"
@@ -161,48 +158,6 @@ protected:
const ModuleFactory TestModuleTwoDependencies::Factory =
ModuleFactory([]() { return new TestModuleTwoDependencies(); });
-// To generate module unittest flatbuffer headers:
-// $ flatc --cpp module_unittest.fbs
-class TestModuleDumpState : public Module {
-public:
- static const ModuleFactory Factory;
-
- std::string test_string_{"Initial Test String"};
-
-protected:
- void ListDependencies(ModuleList* list) const { list->add<TestModuleNoDependency>(); }
-
- void Start() override {
- EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
-
- // A module is not considered started until Start() finishes
- EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleDumpState>());
- test_module_one_dependency_handler = GetHandler();
- }
-
- void Stop() override {
- EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
-
- // A module is not considered stopped until after Stop() finishes
- EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleDumpState>());
- }
-
- std::string ToString() const override { return std::string("TestModuleDumpState"); }
-
- DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const override {
- auto string = fb_builder->CreateString(test_string_.c_str());
-
- auto builder = ModuleUnitTestDataBuilder(*fb_builder);
- builder.add_title(string);
- auto table = builder.Finish();
-
- return [table](DumpsysDataBuilder* builder) { builder->add_module_unittest_data(table); };
- }
-};
-
-const ModuleFactory TestModuleDumpState::Factory =
- ModuleFactory([]() { return new TestModuleDumpState(); });
-
TEST_F(ModuleTest, no_dependency) {
ModuleList list;
list.add<TestModuleNoDependency>();
@@ -270,38 +225,5 @@ TEST_F(ModuleTest, shutdown_with_unhandled_callback) {
registry_->StopAll();
}
-TEST_F(ModuleTest, dump_state) {
- static const char* title = "Test Dump Title";
- ModuleList list;
- list.add<TestModuleDumpState>();
- registry_->Start(&list, thread_);
-
- ModuleDumper dumper(STDOUT_FILENO, *registry_, title);
-
- std::string output;
- std::ostringstream oss;
- dumper.DumpState(&output, oss);
-
- auto data = flatbuffers::GetRoot<DumpsysData>(output.data());
- EXPECT_STREQ(title, data->title()->c_str());
-
- auto test_data = data->module_unittest_data();
- EXPECT_STREQ("Initial Test String", test_data->title()->c_str());
-
- TestModuleDumpState* test_module = static_cast<TestModuleDumpState*>(
- registry_->Start(&TestModuleDumpState::Factory, nullptr));
- test_module->test_string_ = "A Second Test String";
-
- oss.clear();
- output.clear();
- dumper.DumpState(&output, oss);
-
- data = flatbuffers::GetRoot<DumpsysData>(output.data());
- test_data = data->module_unittest_data();
- EXPECT_STREQ("A Second Test String", test_data->title()->c_str());
-
- registry_->StopAll();
-}
-
} // namespace
} // namespace bluetooth
diff --git a/system/gd/module_unittest.fbs b/system/gd/module_unittest.fbs
deleted file mode 100644
index 3c0a1b6bd0..0000000000
--- a/system/gd/module_unittest.fbs
+++ /dev/null
@@ -1,10 +0,0 @@
-// module_unittest
-namespace bluetooth;
-
-attribute "privacy";
-
-table ModuleUnitTestData {
- title:string (privacy:"Any");
-}
-
-root_type ModuleUnitTestData;
diff --git a/system/gd/module_unittest_generated.h b/system/gd/module_unittest_generated.h
deleted file mode 100644
index 1176e5cbc9..0000000000
--- a/system/gd/module_unittest_generated.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// automatically generated by the FlatBuffers compiler, do not modify
-
-#ifndef FLATBUFFERS_GENERATED_MODULEUNITTEST_BLUETOOTH_H_
-#define FLATBUFFERS_GENERATED_MODULEUNITTEST_BLUETOOTH_H_
-
-#include "flatbuffers/flatbuffers.h"
-
-namespace bluetooth {
-
-struct ModuleUnitTestData;
-struct ModuleUnitTestDataBuilder;
-
-struct ModuleUnitTestData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
- typedef ModuleUnitTestDataBuilder Builder;
- enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_TITLE = 4 };
- const flatbuffers::String* title() const {
- return GetPointer<const flatbuffers::String*>(VT_TITLE);
- }
- bool Verify(flatbuffers::Verifier& verifier) const {
- return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TITLE) &&
- verifier.VerifyString(title()) && verifier.EndTable();
- }
-};
-
-struct ModuleUnitTestDataBuilder {
- typedef ModuleUnitTestData Table;
- flatbuffers::FlatBufferBuilder& fbb_;
- flatbuffers::uoffset_t start_;
- void add_title(flatbuffers::Offset<flatbuffers::String> title) {
- fbb_.AddOffset(ModuleUnitTestData::VT_TITLE, title);
- }
- explicit ModuleUnitTestDataBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) {
- start_ = fbb_.StartTable();
- }
- ModuleUnitTestDataBuilder& operator=(const ModuleUnitTestDataBuilder&);
- flatbuffers::Offset<ModuleUnitTestData> Finish() {
- const auto end = fbb_.EndTable(start_);
- auto o = flatbuffers::Offset<ModuleUnitTestData>(end);
- return o;
- }
-};
-
-inline flatbuffers::Offset<ModuleUnitTestData> CreateModuleUnitTestData(
- flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::Offset<flatbuffers::String> title = 0) {
- ModuleUnitTestDataBuilder builder_(_fbb);
- builder_.add_title(title);
- return builder_.Finish();
-}
-
-inline flatbuffers::Offset<ModuleUnitTestData> CreateModuleUnitTestDataDirect(
- flatbuffers::FlatBufferBuilder& _fbb, const char* title = nullptr) {
- auto title__ = title ? _fbb.CreateString(title) : 0;
- return bluetooth::CreateModuleUnitTestData(_fbb, title__);
-}
-
-inline const bluetooth::ModuleUnitTestData* GetModuleUnitTestData(const void* buf) {
- return flatbuffers::GetRoot<bluetooth::ModuleUnitTestData>(buf);
-}
-
-inline const bluetooth::ModuleUnitTestData* GetSizePrefixedModuleUnitTestData(const void* buf) {
- return flatbuffers::GetSizePrefixedRoot<bluetooth::ModuleUnitTestData>(buf);
-}
-
-inline bool VerifyModuleUnitTestDataBuffer(flatbuffers::Verifier& verifier) {
- return verifier.VerifyBuffer<bluetooth::ModuleUnitTestData>(nullptr);
-}
-
-inline bool VerifySizePrefixedModuleUnitTestDataBuffer(flatbuffers::Verifier& verifier) {
- return verifier.VerifySizePrefixedBuffer<bluetooth::ModuleUnitTestData>(nullptr);
-}
-
-inline void FinishModuleUnitTestDataBuffer(
- flatbuffers::FlatBufferBuilder& fbb,
- flatbuffers::Offset<bluetooth::ModuleUnitTestData> root) {
- fbb.Finish(root);
-}
-
-inline void FinishSizePrefixedModuleUnitTestDataBuffer(
- flatbuffers::FlatBufferBuilder& fbb,
- flatbuffers::Offset<bluetooth::ModuleUnitTestData> root) {
- fbb.FinishSizePrefixed(root);
-}
-
-} // namespace bluetooth
-
-#endif // FLATBUFFERS_GENERATED_MODULEUNITTEST_BLUETOOTH_H_
diff --git a/system/gd/neighbor/Android.bp b/system/gd/neighbor/Android.bp
index 9f4f37ad1b..a8f1b64eb9 100644
--- a/system/gd/neighbor/Android.bp
+++ b/system/gd/neighbor/Android.bp
@@ -14,10 +14,3 @@ filegroup {
"scan.cc",
],
}
-
-filegroup {
- name: "BluetoothFacade_neighbor",
- srcs: [
- "facade/facade.cc",
- ],
-}
diff --git a/system/gd/neighbor/facade/facade.cc b/system/gd/neighbor/facade/facade.cc
deleted file mode 100644
index b3df4a876b..0000000000
--- a/system/gd/neighbor/facade/facade.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2019 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 "neighbor/facade/facade.h"
-
-#include <bluetooth/log.h>
-
-#include <memory>
-
-#include "blueberry/facade/neighbor/facade.grpc.pb.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-namespace bluetooth {
-namespace neighbor {
-namespace facade {
-
-using namespace blueberry::facade::neighbor;
-
-class NeighborFacadeService : public NeighborFacade::Service {
-public:
- NeighborFacadeService(ScanModule* scan_module) : scan_module_(scan_module) {}
-
- ::grpc::Status EnablePageScan(::grpc::ServerContext* /* context */, const EnableMsg* request,
- ::google::protobuf::Empty* /* response */) override {
- if (request->enabled()) {
- scan_module_->SetPageScan();
- } else {
- scan_module_->ClearPageScan();
- }
- return ::grpc::Status::OK;
- }
-
-private:
- ScanModule* scan_module_;
-};
-
-void NeighborFacadeModule::ListDependencies(ModuleList* list) const {
- ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
- list->add<ScanModule>();
-}
-
-void NeighborFacadeModule::Start() {
- ::bluetooth::grpc::GrpcFacadeModule::Start();
- service_ = new NeighborFacadeService(GetDependency<ScanModule>());
-}
-
-void NeighborFacadeModule::Stop() {
- delete service_;
- ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* NeighborFacadeModule::GetService() const { return service_; }
-
-const ModuleFactory NeighborFacadeModule::Factory =
- ::bluetooth::ModuleFactory([]() { return new NeighborFacadeModule(); });
-
-} // namespace facade
-} // namespace neighbor
-} // namespace bluetooth
diff --git a/system/gd/neighbor/facade/facade.h b/system/gd/neighbor/facade/facade.h
deleted file mode 100644
index 92432ed530..0000000000
--- a/system/gd/neighbor/facade/facade.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019 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 <grpc++/grpc++.h>
-
-#include "grpc/grpc_module.h"
-#include "neighbor/scan.h"
-
-namespace bluetooth {
-namespace neighbor {
-namespace facade {
-
-class NeighborFacadeService;
-
-class NeighborFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
-public:
- static const ModuleFactory Factory;
-
- void ListDependencies(ModuleList* list) const override;
- void Start() override;
- void Stop() override;
- ::grpc::Service* GetService() const override;
-
-private:
- NeighborFacadeService* service_;
-};
-
-} // namespace facade
-} // namespace neighbor
-} // namespace bluetooth
diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc
index 112dd68f14..1a899062cd 100644
--- a/system/gd/os/android/metrics.cc
+++ b/system/gd/os/android/metrics.cc
@@ -86,7 +86,7 @@ void LogMetricLinkLayerConnectionEvent(const Address* address, uint32_t connecti
common::ToHexString(cmd_status), common::ToHexString(reason_code),
common::ToHexString(hci_cmd), common::ToHexString(hci_event),
common::ToHexString(hci_ble_event),
- address ? ADDRESS_TO_LOGGABLE_CSTR(*address) : "(NULL)", connection_handle,
+ address ? address->ToRedactedStringForLogging() : "(NULL)", connection_handle,
common::ToHexString(link_type), ret);
}
}
diff --git a/system/gd/os/linux_generic/reactor.cc b/system/gd/os/linux_generic/reactor.cc
index 4fc2ac92b3..13f14dceb1 100644
--- a/system/gd/os/linux_generic/reactor.cc
+++ b/system/gd/os/linux_generic/reactor.cc
@@ -106,13 +106,13 @@ Reactor::Reactor() : epoll_fd_(0), control_fd_(0), is_running_(false) {
epoll_event control_epoll_event = {EPOLLIN, {.ptr = nullptr}};
int result;
RUN_NO_INTR(result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, control_fd_, &control_epoll_event));
- log::assert_that(result != -1, "assert failed: result != -1");
+ log::assert_that(result != -1, "epoll_ctl fail: result={} errno={}", result, strerror(errno));
}
Reactor::~Reactor() {
int result;
RUN_NO_INTR(result = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, control_fd_, nullptr));
- log::assert_that(result != -1, "assert failed: result != -1");
+ log::assert_that(result != -1, "epoll_ctl fail: result={} errno={}", result, strerror(errno));
RUN_NO_INTR(result = close(control_fd_));
log::assert_that(result != -1, "assert failed: result != -1");
@@ -225,7 +225,8 @@ Reactor::Reactable* Reactor::Register(int fd, Closure on_read_ready, Closure on_
};
int register_fd;
RUN_NO_INTR(register_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event));
- log::assert_that(register_fd != -1, "assert failed: register_fd != -1");
+ log::assert_that(register_fd != -1, "epoll_ctl fail: register_fd={} errno={}", register_fd,
+ strerror(errno));
return reactable;
}
@@ -306,7 +307,8 @@ void Reactor::ModifyRegistration(Reactor::Reactable* reactable, ReactOn react_on
};
int modify_fd;
RUN_NO_INTR(modify_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, reactable->fd_, &event));
- log::assert_that(modify_fd != -1, "assert failed: modify_fd != -1");
+ log::assert_that(modify_fd != -1, "epoll_ctl fail: modify_fd={} errno={}", modify_fd,
+ strerror(errno));
}
} // namespace os
diff --git a/system/gd/os/linux_generic/wakelock_manager.cc b/system/gd/os/linux_generic/wakelock_manager.cc
index b8cc9000ba..7cca56201a 100644
--- a/system/gd/os/linux_generic/wakelock_manager.cc
+++ b/system/gd/os/linux_generic/wakelock_manager.cc
@@ -134,9 +134,10 @@ struct WakelockManager::Stats {
total_acquired_interval_ms += delta_ms;
}
- flatbuffers::Offset<WakelockManagerData> GetDumpsysData(
- flatbuffers::FlatBufferBuilder* fb_builder, bool is_native) const {
+ template <typename OutputT>
+ void Dump(OutputT&& out, bool is_native) {
const uint64_t just_now_ms = now_ms();
+
// Compute the last acquired interval if the wakelock is still acquired
uint64_t delta_ms = 0;
uint64_t last_interval_ms = last_acquired_interval_ms;
@@ -154,31 +155,36 @@ struct WakelockManager::Stats {
}
last_interval_ms = delta_ms;
}
+
uint64_t total_interval_ms = total_acquired_interval_ms + delta_ms;
if (acquired_count > 0) {
avg_interval_ms = total_interval_ms / acquired_count;
}
- WakelockManagerDataBuilder builder(*fb_builder);
- builder.add_title(fb_builder->CreateString("Bluetooth Wakelock Statistics"));
- builder.add_is_acquired(is_acquired);
- builder.add_is_native(is_native);
- builder.add_acquired_count(acquired_count);
- builder.add_released_count(released_count);
- builder.add_acquired_error_count(acquired_errors);
- builder.add_released_error_count(released_errors);
- builder.add_last_acquire_error_code(last_acquired_error);
- builder.add_last_release_error_code(last_released_error);
- builder.add_last_acquired_timestamp_millis(last_interval_ms);
- builder.add_last_released_timestamp_millis(last_released_timestamp_ms);
- builder.add_last_interval_millis(last_acquired_interval_ms);
- builder.add_max_interval_millis(max_interval_ms);
- builder.add_min_interval_millis(min_interval_ms);
- builder.add_avg_interval_millis(avg_interval_ms);
- builder.add_total_interval_millis(total_interval_ms);
- builder.add_total_time_since_reset_millis(just_now_ms - last_reset_timestamp_ms);
- return builder.Finish();
+ std::format_to(out, "\nWakelock Dumpsys:\n");
+ std::format_to(out,
+ " is_acquired: {}\n"
+ " is_native: {}\n"
+ " acquired_count: {}\n"
+ " released_count: {}\n"
+ " acquired_error_count: {}\n"
+ " released_error_count: {}\n"
+ " last_acquired_error_code: {}\n"
+ " last_released_error_code: {}\n"
+ " last_acquired_timestamp_ms: {}\n"
+ " last_released_timestamp_ms: {}\n"
+ " last_interval_ms: {}\n"
+ " max_interval_ms: {}\n"
+ " min_interval_ms: {}\n"
+ " avg_interval_ms: {}\n"
+ " total_interval_ms: {}\n"
+ " total_time_since_reeset_ms: {}\n",
+ is_acquired, is_native, acquired_count, released_count, acquired_errors,
+ released_errors, last_acquired_error, last_released_error, last_interval_ms,
+ last_released_timestamp_ms, last_acquired_interval_ms, max_interval_ms,
+ min_interval_ms, avg_interval_ms, total_interval_ms,
+ just_now_ms - last_reset_timestamp_ms);
}
};
@@ -266,10 +272,11 @@ void WakelockManager::CleanUp() {
initialized_ = false;
}
-flatbuffers::Offset<WakelockManagerData> WakelockManager::GetDumpsysData(
- flatbuffers::FlatBufferBuilder* fb_builder) {
+void WakelockManager::Dump(int fd) const {
std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
- return pstats_->GetDumpsysData(fb_builder, is_native_);
+ std::string out;
+ pstats_->Dump(std::back_inserter(out), is_native_);
+ dprintf(fd, "%s", out.c_str());
}
WakelockManager::WakelockManager() : pstats_(std::make_unique<Stats>()) {}
diff --git a/system/gd/os/linux_generic/wakelock_manager_unittest.cc b/system/gd/os/linux_generic/wakelock_manager_unittest.cc
index e070d24fb5..d8b4dbf537 100644
--- a/system/gd/os/linux_generic/wakelock_manager_unittest.cc
+++ b/system/gd/os/linux_generic/wakelock_manager_unittest.cc
@@ -24,20 +24,14 @@
#include <unordered_map>
#include "common/bind.h"
-#include "flatbuffers/flatbuffers.h"
#include "os/handler.h"
#include "os/thread.h"
-#include "wakelock_manager_generated.h"
namespace testing {
-using bluetooth::os::FinishWakelockManagerDataBuffer;
-using bluetooth::os::GetWakelockManagerData;
using bluetooth::os::Handler;
using bluetooth::os::Thread;
using bluetooth::os::WakelockManager;
-using bluetooth::os::WakelockManagerData;
-using bluetooth::os::WakelockManagerDataBuilder;
class TestOsCallouts : public WakelockManager::OsCallouts {
public:
@@ -165,28 +159,8 @@ TEST_F(WakelockManagerTest, test_with_os_callouts_in_a_loop_and_dump) {
ASSERT_THAT(os_callouts.GetNetAcquiredCount(WakelockManager::kBtWakelockId), Optional(Eq(0)));
}
- {
- flatbuffers::FlatBufferBuilder builder(1024);
- auto offset = WakelockManager::Get().GetDumpsysData(&builder);
- FinishWakelockManagerDataBuffer(builder, offset);
- auto data = GetWakelockManagerData(builder.GetBufferPointer());
-
- ASSERT_EQ(data->acquired_count(), 1000);
- ASSERT_EQ(data->released_count(), 1000);
- }
-
WakelockManager::Get().CleanUp();
SyncHandler();
-
- {
- flatbuffers::FlatBufferBuilder builder(1024);
- auto offset = WakelockManager::Get().GetDumpsysData(&builder);
- FinishWakelockManagerDataBuffer(builder, offset);
- auto data = GetWakelockManagerData(builder.GetBufferPointer());
-
- ASSERT_EQ(data->acquired_count(), 0);
- ASSERT_EQ(data->released_count(), 0);
- }
}
} // namespace testing
diff --git a/system/gd/os/logging/log_adapter.h b/system/gd/os/logging/log_adapter.h
index d010fd4c24..0da4866fec 100644
--- a/system/gd/os/logging/log_adapter.h
+++ b/system/gd/os/logging/log_adapter.h
@@ -20,9 +20,6 @@
#include <string>
-#define ADDRESS_TO_LOGGABLE_STR(addr) (addr).ToRedactedStringForLogging()
-#define ADDRESS_TO_LOGGABLE_CSTR(addr) ADDRESS_TO_LOGGABLE_STR(addr).c_str()
-
#define PRIVATE_CELL(number) \
(number.replace(0, (number.size() > 2) ? number.size() - 2 : 0, \
(number.size() > 2) ? number.size() - 2 : 0, '*') \
diff --git a/system/gd/os/rand.h b/system/gd/os/rand.h
index 04e29d30f4..03f29bc815 100644
--- a/system/gd/os/rand.h
+++ b/system/gd/os/rand.h
@@ -40,5 +40,12 @@ inline uint32_t GenerateRandom() {
return ret;
}
+inline uint64_t GenerateRandomUint64() {
+ uint64_t ret{};
+ log::assert_that(RAND_bytes((uint8_t*)(&ret), sizeof(uint64_t)) == 1,
+ "assert failed: RAND_bytes((uint8_t*)(&ret), sizeof(uint64_t)) == 1");
+ return ret;
+}
+
} // namespace os
} // namespace bluetooth
diff --git a/system/gd/os/wakelock_manager.fbs b/system/gd/os/wakelock_manager.fbs
deleted file mode 100644
index 7b85e28044..0000000000
--- a/system/gd/os/wakelock_manager.fbs
+++ /dev/null
@@ -1,26 +0,0 @@
-
-namespace bluetooth.os;
-
-attribute "privacy";
-
-table WakelockManagerData {
- title:string;
- is_acquired:bool;
- is_native:bool;
- acquired_count:int;
- released_count:int;
- acquired_error_count:int;
- released_error_count:int;
- last_acquire_error_code:int;
- last_release_error_code:int;
- last_acquired_timestamp_millis:int64;
- last_released_timestamp_millis:int64;
- last_interval_millis:int64;
- max_interval_millis:int64;
- min_interval_millis:int64;
- avg_interval_millis:int64;
- total_interval_millis:int64;
- total_time_since_reset_millis:int64;
-}
-
-root_type WakelockManagerData;
diff --git a/system/gd/os/wakelock_manager.h b/system/gd/os/wakelock_manager.h
index 7f59895502..d920a5b4b4 100644
--- a/system/gd/os/wakelock_manager.h
+++ b/system/gd/os/wakelock_manager.h
@@ -18,14 +18,11 @@
#pragma once
-#include <flatbuffers/flatbuffers.h>
-
#include <memory>
#include <mutex>
#include <string>
#include "handler.h"
-#include "wakelock_manager_generated.h"
namespace bluetooth {
namespace os {
@@ -73,16 +70,16 @@ public:
// This will NOT clean up the callouts
void CleanUp();
- // Dump wakelock-related debug info to a flat buffer defined in wakelock_manager.fbs
- flatbuffers::Offset<WakelockManagerData> GetDumpsysData(
- flatbuffers::FlatBufferBuilder* fb_builder);
+ /// Write debug information relevant for the wakelock manager
+ /// to the dumpsys output file descriptor.
+ void Dump(int fd) const;
~WakelockManager();
private:
WakelockManager();
- std::recursive_mutex mutex_;
+ mutable std::recursive_mutex mutex_;
bool initialized_ = false;
OsCallouts* os_callouts_ = nullptr;
Handler* os_callouts_handler_ = nullptr;
diff --git a/system/gd/rust/linux/client/src/callbacks.rs b/system/gd/rust/linux/client/src/callbacks.rs
index 0d1d998b7d..e9cd5fb7f4 100644
--- a/system/gd/rust/linux/client/src/callbacks.rs
+++ b/system/gd/rust/linux/client/src/callbacks.rs
@@ -1402,6 +1402,10 @@ impl IBluetoothQACallback for QACallback {
fn on_send_hid_data_completed(&mut self, status: BtStatus) {
print_info!("Send HID data: {:?}", status);
}
+
+ fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus) {
+ print_info!("Send HID virtual unplug: {:?}", status);
+ }
}
impl RPCProxy for QACallback {
diff --git a/system/gd/rust/linux/client/src/command_handler.rs b/system/gd/rust/linux/client/src/command_handler.rs
index f7e6ab63ee..fa98c510be 100644
--- a/system/gd/rust/linux/client/src/command_handler.rs
+++ b/system/gd/rust/linux/client/src/command_handler.rs
@@ -314,6 +314,7 @@ fn build_commands() -> HashMap<String, CommandOption> {
String::from("hid get-report <address> <Input|Output|Feature> <report_id>"),
String::from("hid set-report <address> <Input|Output|Feature> <report_value>"),
String::from("hid send-data <address> <data>"),
+ String::from("hid virtual-unplug <address>"),
],
description: String::from("Socket manager utilities."),
function_pointer: CommandHandler::cmd_hid,
@@ -2044,6 +2045,16 @@ impl CommandHandler {
self.context.lock().unwrap().qa_dbus.as_mut().unwrap().send_hid_data(addr, data);
}
+ "virtual-unplug" => {
+ let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
+ self.context
+ .lock()
+ .unwrap()
+ .qa_dbus
+ .as_mut()
+ .unwrap()
+ .send_hid_virtual_unplug(addr);
+ }
_ => return Err(CommandError::InvalidArgs),
};
diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs
index 6209ee58c4..f9d3ae625a 100644
--- a/system/gd/rust/linux/client/src/dbus_iface.rs
+++ b/system/gd/rust/linux/client/src/dbus_iface.rs
@@ -2583,6 +2583,10 @@ impl IBluetoothQA for BluetoothQADBus {
fn send_hid_data(&self, addr: RawAddress, data: String) {
dbus_generated!()
}
+ #[dbus_method("SendHIDVirtualUnplug")]
+ fn send_hid_virtual_unplug(&self, addr: RawAddress) {
+ dbus_generated!()
+ }
}
#[allow(dead_code)]
@@ -2624,6 +2628,10 @@ impl IBluetoothQACallback for IBluetoothQACallbackDBus {
fn on_send_hid_data_completed(&mut self, status: BtStatus) {
dbus_generated!()
}
+ #[dbus_method("OnSendHIDVirtualUnplugComplete", DBusLog::Disable)]
+ fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus) {
+ dbus_generated!()
+ }
}
#[derive(Clone)]
diff --git a/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs b/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs
index 846c7713b4..d2509567fb 100644
--- a/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs
+++ b/system/gd/rust/linux/mgmt/src/bluetooth_experimental_dbus.rs
@@ -21,9 +21,4 @@ impl IBluetoothExperimental for BluetoothExperimentalDBus {
fn set_ll_privacy(&mut self, enabled: bool) -> bool {
dbus_generated!()
}
-
- #[dbus_method("SetDevCoredump")]
- fn set_devcoredump(&mut self, enabled: bool) -> bool {
- dbus_generated!()
- }
}
diff --git a/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs b/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs
index ca98b2ba9b..9b22d7952a 100644
--- a/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs
+++ b/system/gd/rust/linux/mgmt/src/bluetooth_manager.rs
@@ -302,9 +302,4 @@ impl IBluetoothExperimental for BluetoothManager {
true
}
-
- fn set_devcoredump(&mut self, enabled: bool) -> bool {
- warn!("Set Floss DevCoreDump={}", enabled);
- config_util::write_coredump_state_to_file(enabled)
- }
}
diff --git a/system/gd/rust/linux/mgmt/src/config_util.rs b/system/gd/rust/linux/mgmt/src/config_util.rs
index c7f452bfe3..13ffb243d9 100644
--- a/system/gd/rust/linux/mgmt/src/config_util.rs
+++ b/system/gd/rust/linux/mgmt/src/config_util.rs
@@ -17,12 +17,6 @@ const BTMANAGERD_CONF: &str = "/var/lib/bluetooth/btmanagerd.json";
/// Folder to keep files which override floss configuration
const FLOSS_SYSPROPS_OVERRIDE_DIR: &str = "/var/lib/bluetooth/sysprops.conf.d";
-/// File to store bluetooth devcoredump configuration. This file is used by the
-/// udev rule to copy the devcoredump state to .../device/coredump_enabled sysfs
-/// entry. It is also used by the user-space crash reporter to enable/disable
-/// parsing of the devcoredump.
-const FLOSS_COREDUMP_CONF_PATH: &str = "/var/run/bluetooth/coredump_disabled";
-
/// Key used for default adapter entry.
const DEFAULT_ADAPTER_KEY: &str = "default_adapter";
@@ -252,34 +246,6 @@ pub fn write_floss_address_privacy_enabled(enabled: bool) -> std::io::Result<()>
)
}
-pub fn set_adapter_coredump_state(enabled: bool) -> std::io::Result<()> {
- let data = format!("{}\n", !enabled as i32);
-
- for hci in list_hci_devices_string() {
- let path = format!("{}/{}/device/coredump_disabled", HCI_DEVICES_DIR, hci);
-
- std::fs::write(path, &data)?;
- }
-
- Ok(())
-}
-
-pub fn write_coredump_state_to_file(enabled: bool) -> bool {
- let data = format!("{}\n", !enabled as i32);
-
- if let Err(e) = std::fs::write(FLOSS_COREDUMP_CONF_PATH, data) {
- log::error!("Failed to write devcoredump state (error: {})", e);
- return false;
- }
-
- if let Err(e) = set_adapter_coredump_state(enabled) {
- log::error!("Failed to set devcoredump state (error: {})", e);
- return false;
- }
-
- true
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs b/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs
index 4a38e9ee1b..27b20a76e4 100644
--- a/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs
+++ b/system/gd/rust/linux/mgmt/src/iface_bluetooth_experimental.rs
@@ -2,7 +2,4 @@
pub trait IBluetoothExperimental {
/// Set LL privacy status
fn set_ll_privacy(&mut self, enabled: bool) -> bool;
-
- /// Set devcoredump status
- fn set_devcoredump(&mut self, enabled: bool) -> bool;
}
diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs b/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs
index 192b346e66..48873f4637 100644
--- a/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs
+++ b/system/gd/rust/linux/service/src/iface_bluetooth_qa.rs
@@ -65,6 +65,10 @@ impl IBluetoothQA for IBluetoothQADBus {
fn send_hid_data(&self, addr: RawAddress, data: String) {
dbus_generated!()
}
+ #[dbus_method("SendHIDVirtualUnplug")]
+ fn send_hid_virtual_unplug(&self, addr: RawAddress) {
+ dbus_generated!()
+ }
}
#[dbus_proxy_obj(QACallback, "org.chromium.bluetooth.QACallback")]
@@ -97,4 +101,8 @@ impl IBluetoothQACallback for IBluetoothQACallbackDBus {
fn on_send_hid_data_completed(&mut self, status: BtStatus) {
dbus_generated!()
}
+ #[dbus_method("OnSendHIDVirtualUnplugComplete")]
+ fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus) {
+ dbus_generated!()
+ }
}
diff --git a/system/gd/rust/linux/stack/src/battery_provider_manager.rs b/system/gd/rust/linux/stack/src/battery_provider_manager.rs
index 3946a4f6fc..a9f8a3c984 100644
--- a/system/gd/rust/linux/stack/src/battery_provider_manager.rs
+++ b/system/gd/rust/linux/stack/src/battery_provider_manager.rs
@@ -57,8 +57,20 @@ impl BatteryProviderManager {
}
/// Get the best battery info available for a given device.
- pub fn get_battery_info(&self, remote_address: RawAddress) -> Option<BatterySet> {
- self.battery_info.get(&remote_address)?.pick_best()
+ pub fn get_battery_info(&mut self, remote_address: RawAddress) -> Option<BatterySet> {
+ if let Some(info) = self.battery_info.get(&remote_address) {
+ return info.pick_best();
+ }
+
+ // If no battery info found, refresh and retry
+ self.refresh_battery_info();
+ match self.battery_info.get(&remote_address) {
+ None => {
+ debug!("No battery info found for [{}]", DisplayAddress(&remote_address));
+ return None;
+ }
+ Some(info) => return info.pick_best(),
+ }
}
/// Removes a battery provider callback.
diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs
index 20442315c0..2472368243 100644
--- a/system/gd/rust/linux/stack/src/bluetooth.rs
+++ b/system/gd/rust/linux/stack/src/bluetooth.rs
@@ -995,6 +995,11 @@ impl Bluetooth {
)
}
+ // TODO(b/328675014): Add BtAddrType and BtTransport parameters
+ pub(crate) fn send_hid_virtual_unplug_internal(&mut self, mut addr: RawAddress) -> BtStatus {
+ self.hh.as_mut().unwrap().virtual_unplug(&mut addr, BtAddrType::Public, BtTransport::Auto)
+ }
+
/// Returns all bonded and connected devices.
pub(crate) fn get_bonded_and_connected_devices(&mut self) -> Vec<BluetoothDevice> {
self.remote_devices
diff --git a/system/gd/rust/linux/stack/src/bluetooth_qa.rs b/system/gd/rust/linux/stack/src/bluetooth_qa.rs
index d061187586..dd3ddc27a5 100644
--- a/system/gd/rust/linux/stack/src/bluetooth_qa.rs
+++ b/system/gd/rust/linux/stack/src/bluetooth_qa.rs
@@ -37,9 +37,12 @@ pub trait IBluetoothQA {
/// Sets HID report to the peer.
/// Result will be returned in the callback |OnSetHIDReportComplete|
fn set_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report: String);
- /// Snd HID data report to the peer.
+ /// Sends HID data report to the peer.
/// Result will be returned in the callback |OnSendHIDDataComplete|
fn send_hid_data(&self, addr: RawAddress, data: String);
+ /// Sends HID virtual unplug to the peer.
+ /// Result will be returned in the callback |OnSendHIDVirtualUnplugComplete|
+ fn send_hid_virtual_unplug(&self, addr: RawAddress);
}
pub trait IBluetoothQACallback: RPCProxy {
@@ -50,6 +53,7 @@ pub trait IBluetoothQACallback: RPCProxy {
fn on_get_hid_report_completed(&mut self, status: BtStatus);
fn on_set_hid_report_completed(&mut self, status: BtStatus);
fn on_send_hid_data_completed(&mut self, status: BtStatus);
+ fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus);
}
pub struct BluetoothQA {
@@ -99,6 +103,11 @@ impl BluetoothQA {
cb.on_send_hid_data_completed(status);
});
}
+ pub fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus) {
+ self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| {
+ cb.on_send_hid_virtual_unplug_completed(status);
+ });
+ }
}
impl IBluetoothQA for BluetoothQA {
@@ -166,4 +175,10 @@ impl IBluetoothQA for BluetoothQA {
let _ = txl.send(Message::QaSendHidData(addr, data)).await;
});
}
+ fn send_hid_virtual_unplug(&self, addr: RawAddress) {
+ let txl = self.tx.clone();
+ tokio::spawn(async move {
+ let _ = txl.send(Message::QaSendHidVirtualUnplug(addr)).await;
+ });
+ }
}
diff --git a/system/gd/rust/linux/stack/src/lib.rs b/system/gd/rust/linux/stack/src/lib.rs
index e540e68d3e..8027c1c61f 100644
--- a/system/gd/rust/linux/stack/src/lib.rs
+++ b/system/gd/rust/linux/stack/src/lib.rs
@@ -171,6 +171,7 @@ pub enum Message {
QaGetHidReport(RawAddress, BthhReportType, u8),
QaSetHidReport(RawAddress, BthhReportType, String),
QaSendHidData(RawAddress, String),
+ QaSendHidVirtualUnplug(RawAddress),
// UHid callbacks
UHidHfpOutputCallback(RawAddress, u8, u8),
@@ -589,6 +590,10 @@ impl Stack {
let status = bluetooth.lock().unwrap().send_hid_data_internal(addr, data);
bluetooth_qa.lock().unwrap().on_send_hid_data_completed(status);
}
+ Message::QaSendHidVirtualUnplug(addr) => {
+ let status = bluetooth.lock().unwrap().send_hid_virtual_unplug_internal(addr);
+ bluetooth_qa.lock().unwrap().on_send_hid_virtual_unplug_completed(status);
+ }
// UHid callbacks
Message::UHidHfpOutputCallback(addr, id, data) => {
diff --git a/system/gd/rust/topshim/Android.bp b/system/gd/rust/topshim/Android.bp
index b7d3af79ea..5d0e9c2102 100644
--- a/system/gd/rust/topshim/Android.bp
+++ b/system/gd/rust/topshim/Android.bp
@@ -52,7 +52,6 @@ cc_library_static {
"vc/vc_shim.cc",
],
generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
"cxx-bridge-header",
"libbt_topshim_bridge_header",
],
diff --git a/system/gd/rust/topshim/facade/.gitignore b/system/gd/rust/topshim/facade/.gitignore
deleted file mode 100644
index 7cceb192b2..0000000000
--- a/system/gd/rust/topshim/facade/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*_pb2*.py
diff --git a/system/gd/rust/topshim/facade/Android.bp b/system/gd/rust/topshim/facade/Android.bp
deleted file mode 100644
index 505d5e8624..0000000000
--- a/system/gd/rust/topshim/facade/Android.bp
+++ /dev/null
@@ -1,104 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_bt_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_bt_license"],
-}
-
-rust_defaults {
- name: "bt_topshim_facade.defaults",
- defaults: [
- "gd_rust_defaults",
- ],
- crate_name: "bt_topshim_facade",
- srcs: ["src/main.rs"],
- ld_flags: [
- "-fsanitize-minimal-runtime",
- "-fsanitize=undefined",
- ],
- rustlibs: [
- "libbluetooth_core_rs_for_facade",
- "libbt_common",
- "libbt_topshim",
- "libbt_topshim_facade_protobuf",
- "libclap",
- "libfutures",
- "libgrpcio",
- "liblog_rust",
- "libnix",
- "libnum_traits",
- "libtokio",
- ],
- static_libs: [
- "aics",
- "avrcp-target-service",
- "lib-bt-packets",
- "lib-bt-packets-avrcp",
- "lib-bt-packets-base",
- "libFraunhoferAAC",
- "libbluetooth-dumpsys",
- "libbluetooth-types",
- "libbluetooth_crypto_toolbox",
- "libbluetooth_gd", // Gabeldorsche
- "libbluetooth_log",
- "libbt-audio-asrc",
- "libbt-audio-hal-interface",
- "libbt-bta",
- "libbt-bta-core",
- "libbt-btu-main-thread",
- "libbt-common",
- "libbt-hci",
- "libbt-jni-thread",
- "libbt-sbc-decoder",
- "libbt-sbc-encoder",
- "libbt-stack",
- "libbt-stack-core",
- "libbt_topshim_cxx",
- "libbtcore",
- "libbtdevice",
- "libbte",
- "libbthalutils",
- "libbtif",
- "libbtif-core",
- "libchrome",
- "libevent",
- "libflatbuffers-cpp",
- "libg722codec",
- "liblc3",
- "libopus",
- "libosi",
- "libudrv-uipc",
- ],
- shared_libs: [
- "libaconfig_storage_read_api_cc",
- "libbinder",
- "libcrypto",
- "libcutils",
- "libgrpc++",
- "libgrpc_wrap",
- "liblog",
- "server_configurable_flags",
- ],
- proc_macros: [
- "libpaste",
- ],
-}
-
-rust_binary_host {
- name: "bt_topshim_facade",
- defaults: ["bt_topshim_facade.defaults"],
- static_libs: [
- "bluetooth_flags_c_lib",
- ],
-}
-
-rust_test_host {
- name: "bt_topshim_facade.test",
- defaults: ["bt_topshim_facade.defaults"],
- static_libs: [
- "bluetooth_flags_c_lib_for_test",
- ],
- test_suites: ["general-tests"],
-}
diff --git a/system/gd/rust/topshim/facade/src/adapter_service.rs b/system/gd/rust/topshim/facade/src/adapter_service.rs
deleted file mode 100644
index bd56ea5bad..0000000000
--- a/system/gd/rust/topshim/facade/src/adapter_service.rs
+++ /dev/null
@@ -1,385 +0,0 @@
-//! Adapter service facade
-
-use bt_topshim::btif;
-use bt_topshim::btif::{BaseCallbacks, BaseCallbacksDispatcher, BluetoothInterface, BtIoCap};
-
-use crate::utils::converters::{bluetooth_property_to_event_data, event_data_from_string};
-use bt_topshim_facade_protobuf::empty::Empty;
-use bt_topshim_facade_protobuf::facade::{
- EventType, FetchEventsRequest, FetchEventsResponse, SetDefaultEventMaskExceptRequest,
- SetDiscoveryModeRequest, SetLocalIoCapsRequest, SetLocalIoCapsResponse, ToggleDiscoveryRequest,
- ToggleDiscoveryResponse, ToggleStackRequest, ToggleStackResponse,
-};
-use bt_topshim_facade_protobuf::facade_grpc::{create_adapter_service, AdapterService};
-use futures::sink::SinkExt;
-use grpcio::*;
-use num_traits::cast::FromPrimitive;
-
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-use tokio::sync::mpsc;
-use tokio::sync::Mutex as TokioMutex;
-
-fn get_bt_dispatcher(
- btif: Arc<Mutex<BluetoothInterface>>,
- tx: mpsc::Sender<BaseCallbacks>,
-) -> BaseCallbacksDispatcher {
- BaseCallbacksDispatcher {
- dispatch: Box::new(move |cb: BaseCallbacks| {
- if tx.clone().try_send(cb.clone()).is_err() {
- println!("Cannot send event {:?}", cb);
- }
- match cb {
- BaseCallbacks::AdapterState(state) => {
- println!("State changed to {:?}", state);
- }
- BaseCallbacks::SspRequest(addr, variant, passkey) => {
- println!(
- "SSP Request made for address {:?} with variant {:?} and passkey {:?}",
- addr.to_string(),
- variant,
- passkey
- );
- btif.lock().unwrap().ssp_reply(&addr, variant, 1, passkey);
- }
- BaseCallbacks::AdapterProperties(status, _, properties) => {
- println!(
- "Adapter attributes changed, status = {:?}, properties = {:?}",
- status, properties
- );
- }
- BaseCallbacks::DiscoveryState(state) => {
- println!("Discovery state changed, state = {:?}, ", state);
- }
- BaseCallbacks::DeviceFound(_, properties) => {
- println!("Device found with properties : {:?}", properties)
- }
- BaseCallbacks::BondState(_, address, state, _) => {
- println!(
- "Device in state {:?} with device address {}",
- state,
- address.to_string()
- );
- }
- _ => (),
- }
- }),
- }
-}
-
-/// Main object for Adapter facade service
-#[derive(Clone)]
-pub struct AdapterServiceImpl {
- #[allow(dead_code)]
- rt: Arc<Runtime>,
- btif_intf: Arc<Mutex<BluetoothInterface>>,
- event_rx: Arc<TokioMutex<mpsc::Receiver<BaseCallbacks>>>,
- #[allow(dead_code)]
- event_tx: mpsc::Sender<BaseCallbacks>,
-}
-
-fn encode_hex(bytes: &[u8]) -> String {
- let mut s = String::with_capacity(2 * bytes.len());
- for &b in bytes {
- let bstr: String = format!("{:02X}", b);
- s.push_str(&bstr);
- }
- s
-}
-
-impl AdapterServiceImpl {
- /// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
- let (event_tx, rx) = mpsc::channel(10);
- btif_intf
- .lock()
- .unwrap()
- .initialize(get_bt_dispatcher(btif_intf.clone(), event_tx.clone()), 0);
- create_adapter_service(Self {
- rt,
- btif_intf,
- event_rx: Arc::new(TokioMutex::new(rx)),
- event_tx,
- })
- }
-}
-
-impl AdapterService for AdapterServiceImpl {
- fn fetch_events(
- &mut self,
- ctx: RpcContext<'_>,
- _req: FetchEventsRequest,
- mut sink: ServerStreamingSink<FetchEventsResponse>,
- ) {
- let rx = self.event_rx.clone();
- ctx.spawn(async move {
- while let Some(event) = rx.lock().await.recv().await {
- match event {
- BaseCallbacks::AdapterState(_state) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::ADAPTER_STATE.into();
- rsp.params.insert(
- String::from("state"),
- event_data_from_string(String::from("ON")),
- );
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- BaseCallbacks::SspRequest(_, _, _) => {}
- BaseCallbacks::LeRandCallback(random) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::LE_RAND.into();
- rsp.params.insert(
- String::from("data"),
- event_data_from_string(random.to_string()),
- );
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- BaseCallbacks::GenerateLocalOobData(transport, data) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::GENERATE_LOCAL_OOB_DATA.into();
- rsp.params.insert(
- String::from("is_valid"),
- event_data_from_string(String::from(if data.is_valid {
- "1"
- } else {
- "0"
- })),
- );
- rsp.params.insert(
- String::from("transport"),
- event_data_from_string(format!("{}", transport)),
- );
- rsp.params.insert(
- String::from("address"),
- event_data_from_string(encode_hex(&data.address)),
- );
- rsp.params.insert(
- String::from("confirmation"),
- event_data_from_string(encode_hex(&data.c)),
- );
- rsp.params.insert(
- String::from("randomizer"),
- event_data_from_string(encode_hex(&data.r)),
- );
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- BaseCallbacks::AdapterProperties(status, _, properties) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::ADAPTER_PROPERTY.into();
- rsp.params.insert(
- String::from("status"),
- event_data_from_string(format!("{:?}", status)),
- );
- for property in properties.clone() {
- let (key, event_data) = bluetooth_property_to_event_data(property);
- if key == "skip" {
- continue;
- }
- rsp.params.insert(key, event_data);
- }
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- BaseCallbacks::DiscoveryState(state) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::DISCOVERY_STATE.into();
- rsp.params.insert(
- String::from("discovery_state"),
- event_data_from_string(format!("{:?}", state)),
- );
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- BaseCallbacks::DeviceFound(_, properties) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::DEVICE_FOUND.into();
- for property in properties.clone() {
- let (key, event_data) = bluetooth_property_to_event_data(property);
- if key == "skip" {
- continue;
- }
- rsp.params.insert(key, event_data);
- }
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- BaseCallbacks::BondState(_, address, state, _) => {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::BOND_STATE.into();
- rsp.params.insert(
- String::from("bond_state"),
- event_data_from_string(format!("{:?}", state)),
- );
- rsp.params.insert(
- String::from("address"),
- event_data_from_string(address.to_string()),
- );
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- _ => (),
- }
- }
- })
- }
-
- fn toggle_stack(
- &mut self,
- ctx: RpcContext<'_>,
- req: ToggleStackRequest,
- sink: UnarySink<ToggleStackResponse>,
- ) {
- match req.start_stack {
- true => self.btif_intf.lock().unwrap().enable(),
- false => self.btif_intf.lock().unwrap().disable(),
- };
- ctx.spawn(async move {
- sink.success(ToggleStackResponse::default()).await.unwrap();
- })
- }
-
- fn set_discovery_mode(
- &mut self,
- ctx: RpcContext<'_>,
- req: SetDiscoveryModeRequest,
- sink: UnarySink<Empty>,
- ) {
- let scan_mode = if req.enable_inquiry_scan {
- btif::BtScanMode::ConnectableDiscoverable
- } else if req.enable_page_scan {
- btif::BtScanMode::Connectable
- } else {
- btif::BtScanMode::None_
- };
- self.btif_intf.lock().unwrap().set_scan_mode(scan_mode);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn clear_event_filter(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- self.btif_intf.lock().unwrap().clear_event_filter();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn clear_event_mask(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- self.btif_intf.lock().unwrap().clear_event_mask();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn clear_filter_accept_list(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- self.btif_intf.lock().unwrap().clear_filter_accept_list();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn disconnect_all_acls(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- self.btif_intf.lock().unwrap().disconnect_all_acls();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn le_rand(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- self.btif_intf.lock().unwrap().le_rand();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn allow_wake_by_hid(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- self.btif_intf.lock().unwrap().allow_wake_by_hid();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn restore_filter_accept_list(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- self.btif_intf.lock().unwrap().restore_filter_accept_list();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_default_event_mask_except(
- &mut self,
- ctx: RpcContext<'_>,
- req: SetDefaultEventMaskExceptRequest,
- sink: UnarySink<Empty>,
- ) {
- self.btif_intf.lock().unwrap().set_default_event_mask_except(req.mask, req.le_mask);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_event_filter_inquiry_result_all_devices(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- self.btif_intf.lock().unwrap().set_event_filter_inquiry_result_all_devices();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_event_filter_connection_setup_all_devices(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- self.btif_intf.lock().unwrap().set_event_filter_connection_setup_all_devices();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_local_io_caps(
- &mut self,
- ctx: RpcContext<'_>,
- req: SetLocalIoCapsRequest,
- sink: UnarySink<SetLocalIoCapsResponse>,
- ) {
- let status = self.btif_intf.lock().unwrap().set_adapter_property(
- btif::BluetoothProperty::LocalIoCaps(
- BtIoCap::from_i32(req.io_capability).unwrap_or(BtIoCap::Unknown),
- ),
- );
- let mut resp = SetLocalIoCapsResponse::new();
- resp.status = status;
- ctx.spawn(async move {
- sink.success(resp).await.unwrap();
- })
- }
-
- fn toggle_discovery(
- &mut self,
- ctx: RpcContext<'_>,
- req: ToggleDiscoveryRequest,
- sink: UnarySink<ToggleDiscoveryResponse>,
- ) {
- let status = match req.is_start {
- true => self.btif_intf.lock().unwrap().start_discovery(),
- false => self.btif_intf.lock().unwrap().cancel_discovery(),
- };
- let mut resp = ToggleDiscoveryResponse::new();
- resp.status = status;
- ctx.spawn(async move {
- sink.success(resp).await.unwrap();
- })
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/gatt_service.rs b/system/gd/rust/topshim/facade/src/gatt_service.rs
deleted file mode 100644
index 2c27378e2c..0000000000
--- a/system/gd/rust/topshim/facade/src/gatt_service.rs
+++ /dev/null
@@ -1,745 +0,0 @@
-//! GATT service facade
-
-use bt_topshim::btif::{BluetoothInterface, Uuid};
-use bt_topshim::profiles::gatt::{
- AdvertiseParameters, Gatt, GattFilterParam, PeriodicAdvertisingParameters,
-};
-use bt_topshim::profiles::gatt::{
- GattAdvCallbacksDispatcher, GattAdvInbandCallbacksDispatcher, GattClientCallbacksDispatcher,
- GattScannerCallbacksDispatcher, GattScannerInbandCallbacksDispatcher,
- GattServerCallbacksDispatcher,
-};
-use bt_topshim_facade_protobuf::empty::Empty;
-//use bt_topshim_facade_protobuf::facade::{
-// EventType, FetchEventsRequest, FetchEventsResponse, SetDiscoveryModeRequest,
-// SetDiscoveryModeResponse, ToggleStackRequest, ToggleStackResponse,
-//};
-use bt_topshim_facade_protobuf::facade_grpc::{create_gatt_service, GattService};
-//use futures::sink::SinkExt;
-use crate::btif::RawAddress;
-use grpcio::*;
-
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-use tokio::sync::mpsc;
-use tokio::sync::Mutex as TokioMutex;
-
-struct GattCallbacks {}
-
-/// Main object for GATT facade service
-#[derive(Clone)]
-pub struct GattServiceImpl {
- #[allow(dead_code)]
- rt: Arc<Runtime>,
- #[allow(dead_code)]
- btif_intf: Arc<Mutex<BluetoothInterface>>,
- #[allow(dead_code)]
- gatt: Arc<Mutex<Gatt>>,
- #[allow(dead_code)]
- event_rx: Arc<TokioMutex<mpsc::Receiver<GattCallbacks>>>,
- #[allow(dead_code)]
- event_tx: mpsc::Sender<GattCallbacks>,
-}
-
-impl GattServiceImpl {
- /// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
- let (event_tx, rx) = mpsc::channel(10);
- let btif_clone = btif_intf.clone();
- let me = Self {
- rt,
- btif_intf,
- gatt: Arc::new(Mutex::new(Gatt::new(&btif_clone.lock().unwrap()))),
- event_rx: Arc::new(TokioMutex::new(rx)),
- event_tx,
- };
- me.gatt.lock().unwrap().initialize(
- GattClientCallbacksDispatcher {
- dispatch: Box::new(move |cb| {
- println!("Received Gatt Client Callback: {:?}", cb);
- }),
- },
- GattServerCallbacksDispatcher {
- dispatch: Box::new(move |cb| {
- println!("Received Gatt Server Callback: {:?}", cb);
- }),
- },
- GattScannerCallbacksDispatcher {
- dispatch: Box::new(move |cb| {
- println!("received Gatt scanner callback: {:?}", cb);
- }),
- },
- GattScannerInbandCallbacksDispatcher {
- dispatch: Box::new(move |cb| {
- println!("received Gatt scanner inband callback: {:?}", cb);
- }),
- },
- GattAdvInbandCallbacksDispatcher {
- dispatch: Box::new(move |cb| {
- println!("received Gatt advertiser inband callback: {:?}", cb);
- }),
- },
- GattAdvCallbacksDispatcher {
- dispatch: Box::new(move |cb| {
- println!("received Gatt advertising callback: {:?}", cb);
- }),
- },
- );
-
- create_gatt_service(me)
- }
-
- fn create_raw_address(&self) -> RawAddress {
- RawAddress { address: [0; 6] }
- }
-
- fn create_advertise_parameters(&self) -> AdvertiseParameters {
- AdvertiseParameters {
- advertising_event_properties: 0,
- min_interval: 0,
- max_interval: 0,
- channel_map: 0,
- tx_power: 0,
- primary_advertising_phy: 0,
- secondary_advertising_phy: 0,
- scan_request_notification_enable: 0,
- own_address_type: 0,
- peer_address: self.create_raw_address(),
- peer_address_type: 0,
- discoverable: false,
- }
- }
-
- fn create_periodic_advertising_parameters(&self) -> PeriodicAdvertisingParameters {
- PeriodicAdvertisingParameters {
- enable: false,
- include_adi: false,
- min_interval: 0,
- max_interval: 0,
- periodic_advertising_properties: 0,
- }
- }
-
- fn create_gatt_filter_param(&self) -> GattFilterParam {
- GattFilterParam {
- feat_seln: 0,
- list_logic_type: 0,
- filt_logic_type: 0,
- rssi_high_thres: 0,
- rssi_low_thres: 0,
- dely_mode: 0,
- found_timeout: 0,
- lost_timeout: 0,
- found_timeout_cnt: 0,
- num_of_tracking_entries: 0,
- }
- }
-
- fn create_uuid(&self) -> Uuid {
- Uuid::from([0; 16])
- }
-}
-
-impl GattService for GattServiceImpl {
- // fn fetch_events(
- // &mut self,
- // ctx: RpcContext<'_>,
- // _req: FetchEventsRequest,
- // mut sink: ServerStreamingSink<FetchEventsResponse>,
- // ) {
- // let rx = self.event_rx.clone();
- // ctx.spawn(async move {
- // while let Some(event) = rx.lock().await.recv().await {
- // match event {
- // GattCallbacks::AdapterState(_state) => {
- // let mut rsp = FetchEventsResponse::new();
- // rsp.event_type = EventType::ADAPTER_STATE;
- // rsp.data = "ON".to_string();
- // sink.send((rsp, WriteFlags::default())).await.unwrap();
- // }
- // GattCallbacks::SspRequest(_, _, _, _, _) => {}
- // GattCallbacks::LeRandCallback(random) => {
- // let mut rsp = FetchEventsResponse::new();
- // rsp.event_type = EventType::LE_RAND;
- // rsp.data = random.to_string();
- // sink.send((rsp, WriteFlags::default())).await.unwrap();
- // }
- // _ => (),
- // }
- // }
- // })
- // }
-
- // TODO(optedoblivion): Implement all send messages and returns
- // Advertising
- fn register_advertiser(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.register_advertiser();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn unregister_advertiser(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.unregister(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn get_own_address(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.get_own_address(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_parameters(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.set_parameters(0, self.create_advertise_parameters());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_data(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.set_data(0, true, vec![0]);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn advertising_enable(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.enable(0, true, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn advertising_disable(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.enable(0, false, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn start_advertising(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.start_advertising(0, self.create_advertise_parameters(), vec![0], vec![0], 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn start_advertising_set(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.start_advertising_set(
- 0,
- self.create_advertise_parameters(),
- vec![0],
- vec![0],
- self.create_periodic_advertising_parameters(),
- vec![0],
- 0,
- 0,
- );
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_periodic_advertising_parameters(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser
- .set_periodic_advertising_parameters(0, self.create_periodic_advertising_parameters());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_periodic_advertising_data(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.set_periodic_advertising_data(0, vec![0]);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_periodic_advertising_enable(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let advertiser = &mut self.gatt.lock().unwrap().advertiser;
- advertiser.set_periodic_advertising_enable(0, true, false);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- // Scanner
- fn register_scanner(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.register_scanner(self.create_uuid());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn unregister_scanner(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.unregister(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn start_scan(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.start_scan();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn stop_scan(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.stop_scan();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn scan_filter_setup(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.scan_filter_setup(0, 0, 0, self.create_gatt_filter_param());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn scan_filter_add(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- println!("Unimplemented!");
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn scan_filter_clear(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.scan_filter_clear(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn scan_filter_enable(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.scan_filter_enable();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn scan_filter_disable(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.scan_filter_disable();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn set_scan_parameters(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.set_scan_parameters(0, 0, 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn batch_scan_config_storage(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.batchscan_config_storage(0, 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn batch_scan_enable(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.batchscan_enable(0, 0, 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn batch_scan_disable(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.batchscan_disable();
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn batch_scan_read_reports(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.batchscan_read_reports(0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn start_sync(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.start_sync(0, self.create_raw_address(), 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn stop_sync(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.stop_sync(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn cancel_create_sync(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.cancel_create_sync(0, self.create_raw_address());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn transfer_sync(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.transfer_sync(self.create_raw_address(), 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn transfer_set_info(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.transfer_set_info(self.create_raw_address(), 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn sync_tx_parameters(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let scanner = &mut self.gatt.lock().unwrap().scanner;
- scanner.sync_tx_parameters(self.create_raw_address(), 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- // GATT Client
- fn register_client(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.register_client(&self.create_uuid(), true);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn unregister_client(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.unregister_client(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn client_connect(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.connect(0, &self.create_raw_address(), 0, true, 0, true, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn client_disconnect(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.disconnect(0, &self.create_raw_address(), 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn refresh(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.refresh(0, &self.create_raw_address());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn search_service(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.search_service(0, None);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn btif_gattc_discover_service_by_uuid(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.btif_gattc_discover_service_by_uuid(0, &self.create_uuid());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn read_characteristic(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.read_characteristic(0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn read_using_characteristic_uuid(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.read_using_characteristic_uuid(0, &self.create_uuid(), 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn write_characteristic(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.write_characteristic(0, 0, 0, 0, &[0]);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn read_descriptor(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.read_descriptor(0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn write_descriptor(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.write_descriptor(0, 0, 0, &[0]);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn execute_write(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.execute_write(0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn register_for_notification(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.register_for_notification(0, &self.create_raw_address(), 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn deregister_for_notification(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.deregister_for_notification(0, &self.create_raw_address(), 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn read_remote_rssi(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.read_remote_rssi(0, &self.create_raw_address());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn get_device_type(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.get_device_type(&self.create_raw_address());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn configure_mtu(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.configure_mtu(0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn conn_parameter_update(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.conn_parameter_update(&self.create_raw_address(), 0, 0, 0, 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn client_set_preferred_phy(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.set_preferred_phy(&self.create_raw_address(), 0, 0, 0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn client_read_phy(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.read_phy(0, &self.create_raw_address());
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn test_command(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- println!("Not implemented!");
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn get_gatt_db(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- let client = &mut self.gatt.lock().unwrap().client;
- client.get_gatt_db(0);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn register_server(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn unregister_server(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn server_connect(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn server_disconnect(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn add_service(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn stop_service(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn delete_service(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn send_indication(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn send_response(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn server_set_preferred_phy(
- &mut self,
- ctx: RpcContext<'_>,
- _req: Empty,
- sink: UnarySink<Empty>,
- ) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn server_read_phy(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/hf_client_service.rs b/system/gd/rust/topshim/facade/src/hf_client_service.rs
deleted file mode 100644
index 1a5faf8ccc..0000000000
--- a/system/gd/rust/topshim/facade/src/hf_client_service.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-//! HF Client service facade
-
-use bt_topshim::btif::{BluetoothInterface, RawAddress, ToggleableProfile};
-use bt_topshim::profiles::hf_client::{BthfClientCallbacksDispatcher, HfClient};
-use bt_topshim_facade_protobuf::facade::{
- ConnectAudioRequest, ConnectAudioResponse, DisconnectAudioRequest, DisconnectAudioResponse,
- StartSlcRequest, StartSlcResponse, StopSlcRequest, StopSlcResponse,
-};
-use bt_topshim_facade_protobuf::facade_grpc::{create_hf_client_service, HfClientService};
-use grpcio::*;
-use num_traits::cast::ToPrimitive;
-
-use std::str::from_utf8;
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-
-fn get_hf_client_dispatcher() -> BthfClientCallbacksDispatcher {
- BthfClientCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
-}
-
-/// Main object for Hf(Hands free) client facade service
-#[derive(Clone)]
-pub struct HfClientServiceImpl {
- #[allow(dead_code)]
- rt: Arc<Runtime>,
- pub hf_client: Arc<Mutex<HfClient>>,
-}
-
-impl HfClientServiceImpl {
- /// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
- let hf_client = Arc::new(Mutex::new(HfClient::new(&btif_intf.lock().unwrap())));
- hf_client.lock().unwrap().initialize(get_hf_client_dispatcher());
- hf_client.lock().unwrap().enable();
- create_hf_client_service(Self { rt, hf_client })
- }
-}
-
-impl HfClientService for HfClientServiceImpl {
- fn start_slc(
- &mut self,
- ctx: RpcContext<'_>,
- req: StartSlcRequest,
- sink: UnarySink<StartSlcResponse>,
- ) {
- let hf_client = self.hf_client.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- let status = hf_client.lock().unwrap().connect(addr);
- let mut resp = StartSlcResponse::new();
- resp.status = status.to_i32().unwrap();
- sink.success(resp).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn stop_slc(
- &mut self,
- ctx: RpcContext<'_>,
- req: StopSlcRequest,
- sink: UnarySink<StopSlcResponse>,
- ) {
- let hf_client = self.hf_client.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- let status = hf_client.lock().unwrap().disconnect(addr);
- let mut resp = StopSlcResponse::new();
- resp.status = status.to_i32().unwrap();
- sink.success(resp).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn connect_audio(
- &mut self,
- ctx: RpcContext<'_>,
- req: ConnectAudioRequest,
- sink: UnarySink<ConnectAudioResponse>,
- ) {
- let hf_client = self.hf_client.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- let status = hf_client.lock().unwrap().connect_audio(addr);
- let mut resp = ConnectAudioResponse::new();
- resp.status = status.to_i32().unwrap();
- sink.success(resp).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn disconnect_audio(
- &mut self,
- ctx: RpcContext<'_>,
- req: DisconnectAudioRequest,
- sink: UnarySink<DisconnectAudioResponse>,
- ) {
- let hf_client = self.hf_client.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- let status = hf_client.lock().unwrap().disconnect_audio(addr);
- let mut resp = DisconnectAudioResponse::new();
- resp.status = status.to_i32().unwrap();
- sink.success(resp).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/hfp_service.rs b/system/gd/rust/topshim/facade/src/hfp_service.rs
deleted file mode 100644
index 4f08a44c50..0000000000
--- a/system/gd/rust/topshim/facade/src/hfp_service.rs
+++ /dev/null
@@ -1,212 +0,0 @@
-//! HFP service facade
-
-use bt_topshim::btif::{BluetoothInterface, RawAddress, ToggleableProfile};
-use bt_topshim::profiles::hfp::{Hfp, HfpCallbacks, HfpCallbacksDispatcher};
-use bt_topshim_facade_protobuf::empty::Empty;
-use bt_topshim_facade_protobuf::facade::{
- ConnectAudioRequest, DisconnectAudioRequest, EventType, FetchEventsRequest,
- FetchEventsResponse, SetVolumeRequest, StartSlcRequest, StopSlcRequest,
-};
-use bt_topshim_facade_protobuf::facade_grpc::{create_hfp_service, HfpService};
-use futures::sink::SinkExt;
-use grpcio::*;
-
-use std::str::from_utf8;
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-use tokio::sync::mpsc;
-
-fn get_hfp_dispatcher(
- _hfp: Arc<Mutex<Hfp>>,
- tx: Arc<Mutex<Option<mpsc::Sender<HfpCallbacks>>>>,
-) -> HfpCallbacksDispatcher {
- HfpCallbacksDispatcher {
- dispatch: Box::new(move |cb: HfpCallbacks| {
- println!("Hfp Callback found {:?}", cb);
- if let HfpCallbacks::ConnectionState(state, address) = &cb {
- println!("Hfp Connection state changed to {:?} for address {:?}", state, address);
- }
- let guard_tx = tx.lock().unwrap();
- if let Some(event_tx) = guard_tx.as_ref() {
- let txclone = event_tx.clone();
- if txclone.try_send(cb.clone()).is_err() {
- println!("Cannot send event {:?}", cb);
- }
- /*tokio::spawn(async move {
- let _ = txclone.send(cb).await;
- });*/
- }
- }),
- }
-}
-
-/// Main object for Hfp facade service
-#[derive(Clone)]
-pub struct HfpServiceImpl {
- #[allow(dead_code)]
- rt: Arc<Runtime>,
- pub btif_hfp: Arc<Mutex<Hfp>>,
- #[allow(dead_code)]
- event_tx: Arc<Mutex<Option<mpsc::Sender<HfpCallbacks>>>>,
-}
-
-impl HfpServiceImpl {
- /// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
- let btif_hfp = Arc::new(Mutex::new(Hfp::new(&btif_intf.lock().unwrap())));
- let event_tx = Arc::new(Mutex::new(None));
- btif_hfp.lock().unwrap().initialize(get_hfp_dispatcher(btif_hfp.clone(), event_tx.clone()));
- btif_hfp.lock().unwrap().enable();
- create_hfp_service(Self { rt, btif_hfp, event_tx })
- }
-}
-
-impl HfpService for HfpServiceImpl {
- fn start_slc(&mut self, ctx: RpcContext<'_>, req: StartSlcRequest, sink: UnarySink<Empty>) {
- let hfp = self.btif_hfp.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- hfp.lock().unwrap().connect(addr);
- sink.success(Empty::default()).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn stop_slc(&mut self, ctx: RpcContext<'_>, req: StopSlcRequest, sink: UnarySink<Empty>) {
- let hfp = self.btif_hfp.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- hfp.lock().unwrap().disconnect(addr);
- sink.success(Empty::default()).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn connect_audio(
- &mut self,
- ctx: RpcContext<'_>,
- req: ConnectAudioRequest,
- sink: UnarySink<Empty>,
- ) {
- let hfp = self.btif_hfp.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- hfp.lock().unwrap().connect_audio(
- addr,
- req.is_sco_offload_enabled,
- req.disabled_codecs,
- );
- hfp.lock().unwrap().set_active_device(addr);
- sink.success(Empty::default()).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn disconnect_audio(
- &mut self,
- ctx: RpcContext<'_>,
- req: DisconnectAudioRequest,
- sink: UnarySink<Empty>,
- ) {
- let hfp = self.btif_hfp.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- hfp.lock().unwrap().disconnect_audio(addr);
- sink.success(Empty::default()).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn set_volume(&mut self, ctx: RpcContext<'_>, req: SetVolumeRequest, sink: UnarySink<Empty>) {
- let hfp = self.btif_hfp.clone();
- ctx.spawn(async move {
- let addr_bytes = &req.connection.unwrap().cookie;
- let bt_addr = from_utf8(addr_bytes).unwrap();
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- // TODO(aritrasen): Consider using TryFrom and cap the maximum volume here
- // since `as` silently deals with data overflow, which might not be preferred.
- hfp.lock().unwrap().set_volume(req.volume as i8, addr);
- sink.success(Empty::default()).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- })
- }
-
- fn fetch_events(
- &mut self,
- ctx: RpcContext<'_>,
- _req: FetchEventsRequest,
- mut sink: ServerStreamingSink<FetchEventsResponse>,
- ) {
- let (tx, mut rx) = mpsc::channel(10);
- {
- let mut guard = self.event_tx.lock().unwrap();
- if guard.is_some() {
- ctx.spawn(async move {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::UNAVAILABLE,
- String::from("Profile is currently already connected and streaming"),
- ))
- .await
- .unwrap();
- });
- return;
- } else {
- *guard = Some(tx);
- }
- }
-
- ctx.spawn(async move {
- while let Some(event) = rx.recv().await {
- if let HfpCallbacks::ConnectionState(state, address) = event {
- let mut rsp = FetchEventsResponse::new();
- rsp.event_type = EventType::HFP_CONNECTION_STATE.into();
- rsp.data = format!("{:?}, {}", state, address.to_string());
- sink.send((rsp, WriteFlags::default())).await.unwrap();
- }
- }
- })
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/main.rs b/system/gd/rust/topshim/facade/src/main.rs
deleted file mode 100644
index a8a9745752..0000000000
--- a/system/gd/rust/topshim/facade/src/main.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-//! Starts the facade services that allow us to test the Bluetooth stack
-
-use bt_topshim::btif;
-
-use clap::{value_parser, Arg, Command};
-use futures::channel::mpsc;
-use futures::executor::block_on;
-use futures::stream::StreamExt;
-use grpcio::*;
-use log::debug;
-use nix::sys::signal;
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-
-mod adapter_service;
-mod gatt_service;
-mod hf_client_service;
-mod hfp_service;
-mod media_service;
-mod security_service;
-mod utils;
-
-// This is needed for linking, libbt_shim_bridge needs symbols defined by
-// bt_shim, however bt_shim depends on rust crates (future, tokio) that
-// we use too, if we build and link them separately we ends with duplicate
-// symbols. To solve that we build bt_shim with bt_topshim_facade so the rust
-// compiler share the transitive dependencies.
-//
-// The `::*` is here to circuvent the single_component_path_imports from
-// clippy that is denied on the rust command line so we can't just allow it.
-// This is fine for now since bt_shim doesn't export anything
-#[allow(unused)]
-use bluetooth_core_rs_for_facade::*;
-
-fn main() {
- // SAFETY: There is no signal handler installed before this.
- let sigint = unsafe { install_sigint() };
- bt_common::init_logging();
- let rt = Arc::new(Runtime::new().unwrap());
- rt.block_on(async_main(Arc::clone(&rt), sigint));
-}
-
-fn clap_command() -> Command {
- Command::new("bluetooth_topshim_facade")
- .about("The bluetooth topshim stack, with testing facades enabled and exposed via gRPC.")
- .arg(
- Arg::new("grpc-port")
- .long("grpc-port")
- .value_parser(value_parser!(u16))
- .default_value("8899"),
- )
- .arg(
- Arg::new("root-server-port")
- .long("root-server-port")
- .value_parser(value_parser!(u16))
- .default_value("8897"),
- )
- .arg(
- Arg::new("signal-port")
- .long("signal-port")
- .value_parser(value_parser!(u16))
- .default_value("8895"),
- )
- .arg(Arg::new("rootcanal-port").long("rootcanal-port").value_parser(value_parser!(u16)))
- .arg(Arg::new("btsnoop").long("btsnoop"))
- .arg(Arg::new("btsnooz").long("btsnooz"))
- .arg(Arg::new("btconfig").long("btconfig"))
- .arg(
- Arg::new("start-stack-now")
- .long("start-stack-now")
- .value_parser(value_parser!(bool))
- .default_value("true"),
- )
-}
-
-async fn async_main(rt: Arc<Runtime>, mut sigint: mpsc::UnboundedReceiver<()>) {
- let matches = clap_command().get_matches();
-
- let grpc_port = *matches.get_one::<u16>("grpc-port").unwrap();
- let _rootcanal_port = matches.get_one::<u16>("rootcanal-port").cloned();
- let env = Arc::new(Environment::new(2));
-
- let btif_intf = Arc::new(Mutex::new(btif::get_btinterface()));
-
- // AdapterServiceImpl::create initializes the stack; not the best practice because the side effect is hidden
- let adapter_service_impl =
- adapter_service::AdapterServiceImpl::create(rt.clone(), btif_intf.clone());
-
- let security_service_impl =
- security_service::SecurityServiceImpl::create(rt.clone(), btif_intf.clone());
-
- let gatt_service_impl = gatt_service::GattServiceImpl::create(rt.clone(), btif_intf.clone());
-
- let hf_client_service_impl =
- hf_client_service::HfClientServiceImpl::create(rt.clone(), btif_intf.clone());
-
- let hfp_service_impl = hfp_service::HfpServiceImpl::create(rt.clone(), btif_intf.clone());
-
- let media_service_impl = media_service::MediaServiceImpl::create(rt.clone(), btif_intf.clone());
-
- let start_stack_now = *matches.get_one::<bool>("start-stack-now").unwrap();
-
- if start_stack_now {
- btif_intf.clone().lock().unwrap().enable();
- }
-
- let mut server = ServerBuilder::new(env)
- .register_service(adapter_service_impl)
- .register_service(security_service_impl)
- .register_service(gatt_service_impl)
- .register_service(hf_client_service_impl)
- .register_service(hfp_service_impl)
- .register_service(media_service_impl)
- .build()
- .unwrap();
- let addr = format!("0.0.0.0:{}", grpc_port);
- let creds = ServerCredentials::insecure();
- server.add_listening_port(addr, creds).unwrap();
- server.start();
-
- sigint.next().await;
- block_on(server.shutdown()).unwrap();
-}
-
-// TODO: remove as this is a temporary nix-based hack to catch SIGINT
-/// # Safety
-///
-/// The old signal handler, if any, must be installed correctly.
-unsafe fn install_sigint() -> mpsc::UnboundedReceiver<()> {
- let (tx, rx) = mpsc::unbounded();
- *SIGINT_TX.lock().unwrap() = Some(tx);
-
- let sig_action = signal::SigAction::new(
- signal::SigHandler::Handler(handle_sigint),
- signal::SaFlags::empty(),
- signal::SigSet::empty(),
- );
- // SAFETY: The caller guarantees that the old signal handler was installed correctly.
- // TODO(b/292218119): Make sure `handle_sigint` only makes system calls that are safe for signal
- // handlers, and only accesses global state through atomics. In particular, it must not take any
- // shared locks.
- unsafe {
- signal::sigaction(signal::SIGINT, &sig_action).unwrap();
- }
-
- rx
-}
-
-static SIGINT_TX: Mutex<Option<mpsc::UnboundedSender<()>>> = Mutex::new(None);
-
-extern "C" fn handle_sigint(_: i32) {
- let mut sigint_tx = SIGINT_TX.lock().unwrap();
- if let Some(tx) = &*sigint_tx {
- debug!("Stopping gRPC root server due to SIGINT");
- tx.unbounded_send(()).unwrap();
- }
- *sigint_tx = None;
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn verify_comand() {
- clap_command().debug_assert();
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/media_service.rs b/system/gd/rust/topshim/facade/src/media_service.rs
deleted file mode 100644
index aba1a21f94..0000000000
--- a/system/gd/rust/topshim/facade/src/media_service.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-//! Media service facade
-
-use bt_topshim::btif::{BluetoothInterface, RawAddress};
-use bt_topshim::profiles::a2dp::{
- A2dp, A2dpCallbacksDispatcher, A2dpSink, A2dpSinkCallbacksDispatcher,
-};
-use bt_topshim::profiles::avrcp::{Avrcp, AvrcpCallbacksDispatcher};
-use bt_topshim_facade_protobuf::facade::{
- A2dpSourceConnectRequest, A2dpSourceConnectResponse, StartA2dpRequest, StartA2dpResponse,
-};
-use bt_topshim_facade_protobuf::facade_grpc::{create_media_service, MediaService};
-
-use grpcio::*;
-
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-
-fn get_a2dp_dispatcher() -> A2dpCallbacksDispatcher {
- A2dpCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
-}
-
-fn get_a2dp_sink_dispatcher() -> A2dpSinkCallbacksDispatcher {
- A2dpSinkCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
-}
-
-fn get_avrcp_dispatcher() -> AvrcpCallbacksDispatcher {
- AvrcpCallbacksDispatcher { dispatch: Box::new(move |_cb| {}) }
-}
-
-/// Main object for Media facade service
-#[derive(Clone)]
-pub struct MediaServiceImpl {
- #[allow(dead_code)]
- rt: Arc<Runtime>,
- pub btif_a2dp: Arc<Mutex<A2dp>>,
- btif_a2dp_sink: Arc<Mutex<A2dpSink>>,
- #[allow(dead_code)]
- pub btif_avrcp: Arc<Mutex<Avrcp>>,
-}
-
-impl MediaServiceImpl {
- /// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
- let mut btif_a2dp = A2dp::new(&btif_intf.lock().unwrap());
- let btif_a2dp_sink = A2dpSink::new(&btif_intf.lock().unwrap());
- let mut btif_avrcp = Avrcp::new(&btif_intf.lock().unwrap());
- btif_a2dp.initialize(get_a2dp_dispatcher());
- btif_avrcp.initialize(get_avrcp_dispatcher());
-
- create_media_service(Self {
- rt,
- btif_a2dp: Arc::new(Mutex::new(btif_a2dp)),
- btif_a2dp_sink: Arc::new(Mutex::new(btif_a2dp_sink)),
- btif_avrcp: Arc::new(Mutex::new(btif_avrcp)),
- })
- }
-}
-
-impl MediaService for MediaServiceImpl {
- fn start_a2dp(
- &mut self,
- ctx: RpcContext<'_>,
- req: StartA2dpRequest,
- sink: UnarySink<StartA2dpResponse>,
- ) {
- if req.start_a2dp_source {
- ctx.spawn(async move {
- sink.success(StartA2dpResponse::default()).await.unwrap();
- })
- } else if req.start_a2dp_sink {
- self.btif_a2dp_sink.lock().unwrap().initialize(get_a2dp_sink_dispatcher());
- ctx.spawn(async move {
- sink.success(StartA2dpResponse::default()).await.unwrap();
- })
- }
- }
-
- fn a2dp_source_connect(
- &mut self,
- ctx: RpcContext<'_>,
- req: A2dpSourceConnectRequest,
- sink: UnarySink<A2dpSourceConnectResponse>,
- ) {
- let a2dp = self.btif_a2dp.clone();
- ctx.spawn(async move {
- if let Some(addr) = RawAddress::from_string(req.address.clone()) {
- a2dp.lock().unwrap().connect(addr);
- a2dp.lock().unwrap().set_active_device(addr);
- sink.success(A2dpSourceConnectResponse::default()).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", req.address),
- ))
- .await
- .unwrap();
- }
- })
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/security_service.rs b/system/gd/rust/topshim/facade/src/security_service.rs
deleted file mode 100644
index e378a777ff..0000000000
--- a/system/gd/rust/topshim/facade/src/security_service.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-//! Security service facade
-
-use bt_topshim::btif::{BluetoothInterface, BtTransport, RawAddress};
-
-use bt_topshim_facade_protobuf::empty::Empty;
-use bt_topshim_facade_protobuf::facade::{
- CreateBondRequest, CreateBondResponse, GenerateOobDataRequest, RemoveBondRequest,
-};
-use bt_topshim_facade_protobuf::facade_grpc::{create_security_service, SecurityService};
-use grpcio::*;
-
-use std::sync::{Arc, Mutex};
-use tokio::runtime::Runtime;
-
-/// Main object for Adapter facade service
-#[derive(Clone)]
-pub struct SecurityServiceImpl {
- #[allow(dead_code)]
- rt: Arc<Runtime>,
- #[allow(dead_code)]
- btif_intf: Arc<Mutex<BluetoothInterface>>,
-}
-
-#[allow(dead_code)]
-impl SecurityServiceImpl {
- /// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>, btif_intf: Arc<Mutex<BluetoothInterface>>) -> grpcio::Service {
- create_security_service(Self { rt, btif_intf })
- }
-}
-
-impl SecurityService for SecurityServiceImpl {
- fn remove_bond(&mut self, ctx: RpcContext<'_>, req: RemoveBondRequest, sink: UnarySink<Empty>) {
- let raw_address = RawAddress::from_string(req.address).unwrap();
- self.btif_intf.lock().unwrap().remove_bond(&raw_address);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn generate_local_oob_data(
- &mut self,
- ctx: RpcContext<'_>,
- req: GenerateOobDataRequest,
- sink: UnarySink<Empty>,
- ) {
- self.btif_intf.lock().unwrap().generate_local_oob_data(req.transport);
- ctx.spawn(async move {
- sink.success(Empty::default()).await.unwrap();
- })
- }
-
- fn create_bond(
- &mut self,
- ctx: RpcContext<'_>,
- req: CreateBondRequest,
- sink: UnarySink<CreateBondResponse>,
- ) {
- let btif = self.btif_intf.clone();
- ctx.spawn(async move {
- let bt_addr = &req.address;
- if let Some(addr) = RawAddress::from_string(bt_addr) {
- let status =
- btif.lock().unwrap().create_bond(&addr, BtTransport::from(req.transport));
- let mut resp = CreateBondResponse::new();
- resp.status = status;
- sink.success(resp).await.unwrap();
- } else {
- sink.fail(RpcStatus::with_message(
- RpcStatusCode::INVALID_ARGUMENT,
- format!("Invalid Request Address: {}", bt_addr),
- ))
- .await
- .unwrap();
- }
- });
- }
-}
diff --git a/system/gd/rust/topshim/facade/src/utils.rs b/system/gd/rust/topshim/facade/src/utils.rs
deleted file mode 100644
index 31d5d773b7..0000000000
--- a/system/gd/rust/topshim/facade/src/utils.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! Utility modules and functions for facade services.
-
-pub mod converters {
- use bt_topshim::btif::BluetoothProperty;
- use bt_topshim_facade_protobuf::facade::EventData;
-
- pub fn bluetooth_property_to_event_data(property: BluetoothProperty) -> (String, EventData) {
- match property {
- BluetoothProperty::BdName(name) => {
- (String::from("BdName"), event_data_from_string(name))
- }
- BluetoothProperty::BdAddr(address) => {
- (String::from("BdAddr"), event_data_from_string(address.to_string()))
- }
- BluetoothProperty::Uuids(uuids) => {
- let mut event = EventData::new();
- for uuid in uuids {
- event.data.push(format!("{:?}", uuid));
- }
- (String::from("Uuids"), event)
- }
- BluetoothProperty::LocalIoCaps(caps) => {
- (String::from("LocalIoCaps"), event_data_from_string(format!("{:?}", caps)))
- }
- _ => (String::from("skip"), EventData::new()),
- }
- }
-
- pub fn event_data_from_string(data: String) -> EventData {
- let mut event = EventData::new();
- event.data.push(data);
- event
- }
-}
diff --git a/system/gd/rust/topshim/macros/src/lib.rs b/system/gd/rust/topshim/macros/src/lib.rs
index 65aa24ddb1..78fc677491 100644
--- a/system/gd/rust/topshim/macros/src/lib.rs
+++ b/system/gd/rust/topshim/macros/src/lib.rs
@@ -103,17 +103,13 @@ pub fn cb_variant(input: TokenStream) -> TokenStream {
let ident = format_ident!("_{}", i);
params.extend(quote! { #ident: #start, });
- match end {
- Some(v) => {
- // Argument needs an into translation if it doesn't match the start
- if start != v {
- args.extend(quote! { #end::from(#ident), });
- } else {
- args.extend(quote! {#ident,});
- }
+ if let Some(v) = end {
+ // Argument needs an into translation if it doesn't match the start
+ if start != v {
+ args.extend(quote! { #end::from(#ident), });
+ } else {
+ args.extend(quote! {#ident,});
}
- // If there's no end type, just consume it instead.
- None => (),
}
}
diff --git a/system/gd/rust/topshim/src/profiles/gatt.rs b/system/gd/rust/topshim/src/profiles/gatt.rs
index a6884310b6..7bed7bdf78 100644
--- a/system/gd/rust/topshim/src/profiles/gatt.rs
+++ b/system/gd/rust/topshim/src/profiles/gatt.rs
@@ -2,8 +2,8 @@ use crate::bindings::root as bindings;
use crate::btif::{ptr_to_vec, BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, Uuid};
use crate::profiles::gatt::bindings::{
btgatt_callbacks_t, btgatt_client_callbacks_t, btgatt_client_interface_t, btgatt_interface_t,
- btgatt_scanner_callbacks_t, btgatt_server_callbacks_t, btgatt_server_interface_t,
- BleAdvertiserInterface, BleScannerInterface,
+ btgatt_server_callbacks_t, btgatt_server_interface_t, BleAdvertiserInterface,
+ BleScannerInterface,
};
use crate::topstack::get_dispatchers;
use crate::utils::LTCheckedPtr;
@@ -1723,7 +1723,6 @@ pub struct Gatt {
callbacks: Option<Box<bindings::btgatt_callbacks_t>>,
gatt_client_callbacks: Option<Box<bindings::btgatt_client_callbacks_t>>,
gatt_server_callbacks: Option<Box<bindings::btgatt_server_callbacks_t>>,
- gatt_scanner_callbacks: Option<Box<bindings::btgatt_scanner_callbacks_t>>,
}
impl Gatt {
@@ -1759,7 +1758,6 @@ impl Gatt {
callbacks: None,
gatt_client_callbacks: None,
gatt_server_callbacks: None,
- gatt_scanner_callbacks: None,
}
}
@@ -1869,18 +1867,10 @@ impl Gatt {
subrate_chg_cb: Some(gs_subrate_chg_cb),
});
- let gatt_scanner_callbacks = Box::new(btgatt_scanner_callbacks_t {
- scan_result_cb: None,
- batchscan_reports_cb: None,
- batchscan_threshold_cb: None,
- track_adv_event_cb: None,
- });
-
let callbacks = Box::new(btgatt_callbacks_t {
size: std::mem::size_of::<btgatt_callbacks_t>(),
client: &*gatt_client_callbacks,
server: &*gatt_server_callbacks,
- scanner: &*gatt_scanner_callbacks,
});
let cb_ptr = LTCheckedPtr::from(&callbacks);
@@ -1890,7 +1880,6 @@ impl Gatt {
self.callbacks = Some(callbacks);
self.gatt_client_callbacks = Some(gatt_client_callbacks);
self.gatt_server_callbacks = Some(gatt_server_callbacks);
- self.gatt_scanner_callbacks = Some(gatt_scanner_callbacks);
// Register callbacks for gatt scanner and advertiser
mutcxxcall!(self.scanner, RegisterCallbacks);
diff --git a/system/gd/rust/topshim/src/profiles/socket.rs b/system/gd/rust/topshim/src/profiles/socket.rs
index 49a0f15cde..d8cfd4590a 100644
--- a/system/gd/rust/topshim/src/profiles/socket.rs
+++ b/system/gd/rust/topshim/src/profiles/socket.rs
@@ -164,6 +164,12 @@ impl BtSocket {
let name = CString::new(service_name).expect("Service name has null in it.");
let name_ptr = LTCheckedPtr::from(&name);
+ let data_path: u32 = 0;
+ let sock_name = CString::new("test").expect("Socket name has null in it");
+ let hub_id: u64 = 0;
+ let endpoint_id: u64 = 0;
+ let max_rx_packet_size: i32 = 0;
+
let status: BtStatus = ccall!(
self,
listen,
@@ -173,7 +179,12 @@ impl BtSocket {
channel,
sockfd_ptr.into(),
flags,
- calling_uid
+ calling_uid,
+ data_path,
+ sock_name.as_ptr(),
+ hub_id,
+ endpoint_id,
+ max_rx_packet_size
)
.into();
@@ -194,6 +205,12 @@ impl BtSocket {
let uuid_ptr = LTCheckedPtr::from(&service_uuid);
let addr_ptr = LTCheckedPtr::from_ref(&addr);
+ let data_path: u32 = 0;
+ let sock_name = CString::new("test").expect("Socket name has null in it");
+ let hub_id: u64 = 0;
+ let endpoint_id: u64 = 0;
+ let max_rx_packet_size: i32 = 0;
+
let status: BtStatus = ccall!(
self,
connect,
@@ -203,7 +220,12 @@ impl BtSocket {
channel,
sockfd_ptr.into(),
flags,
- calling_uid
+ calling_uid,
+ data_path,
+ sock_name.as_ptr(),
+ hub_id,
+ endpoint_id,
+ max_rx_packet_size
)
.into();
@@ -274,6 +296,7 @@ mod tests {
max_rx_packet_size: 17_u16,
conn_uuid_lsb: 0x0000113500001135_u64,
conn_uuid_msb: 0x1135000011350000_u64,
+ socket_id: 0x1135113511351135_u64,
};
// SAFETY: The sock_connect_signal_t type has size CONNECT_COMPLETE_SIZE,
// and has no padding, so it's safe to convert it to a byte array.
diff --git a/system/gd/shim/dumpsys.cc b/system/gd/shim/dumpsys.cc
deleted file mode 100644
index ae5d2c9fad..0000000000
--- a/system/gd/shim/dumpsys.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright 2019 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 "bt_gd_shim"
-
-#include "dumpsys/dumpsys.h"
-
-#include <bluetooth/log.h>
-#include <com_android_bluetooth_flags.h>
-#include <unistd.h>
-
-#include <future>
-#include <sstream>
-#include <string>
-
-#include "dumpsys/filter.h"
-#include "hal/snoop_logger.h"
-#include "hci/acl_manager.h"
-#include "hci/controller_interface.h"
-#include "main/shim/entry.h"
-#include "main/shim/stack.h"
-#include "module.h"
-#include "module_dumper.h"
-#include "os/system_properties.h"
-#include "shim/dumpsys.h"
-
-namespace bluetooth {
-namespace shim {
-
-static const std::string kReadOnlyDebuggableProperty = "ro.debuggable";
-
-namespace {
-constexpr char kModuleName[] = "shim::Dumpsys";
-constexpr char kDumpsysTitle[] = "----- Gd Dumpsys ------";
-} // namespace
-
-struct Dumpsys::impl {
-public:
- void DumpWithArgsSync(int fd, const char** args, std::promise<void> promise);
- int GetNumberOfBundledSchemas() const;
-
- impl(const Dumpsys& dumpsys_module, const dumpsys::ReflectionSchema& reflection_schema);
- ~impl() = default;
-
-protected:
- void FilterSchema(std::string* dumpsys_data) const;
- std::string PrintAsJson(std::string* dumpsys_data) const;
-
- bool IsDebuggable() const;
-
-private:
- void DumpWithArgsAsync(int fd, const char** args) const;
-
- const Dumpsys& dumpsys_module_;
- const dumpsys::ReflectionSchema reflection_schema_;
-};
-
-const ModuleFactory Dumpsys::Factory =
- ModuleFactory([]() { return new Dumpsys(bluetooth::dumpsys::GetBundledSchemaData()); });
-
-Dumpsys::impl::impl(const Dumpsys& dumpsys_module,
- const dumpsys::ReflectionSchema& reflection_schema)
- : dumpsys_module_(dumpsys_module), reflection_schema_(std::move(reflection_schema)) {}
-
-int Dumpsys::impl::GetNumberOfBundledSchemas() const {
- return reflection_schema_.GetNumberOfBundledSchemas();
-}
-
-bool Dumpsys::impl::IsDebuggable() const {
- return os::GetSystemProperty(kReadOnlyDebuggableProperty) == "1";
-}
-
-void Dumpsys::impl::FilterSchema(std::string* dumpsys_data) const {
- log::assert_that(dumpsys_data != nullptr, "assert failed: dumpsys_data != nullptr");
- dumpsys::FilterSchema(reflection_schema_, dumpsys_data);
-}
-
-std::string Dumpsys::impl::PrintAsJson(std::string* dumpsys_data) const {
- log::assert_that(dumpsys_data != nullptr, "assert failed: dumpsys_data != nullptr");
-
- const std::string root_name = reflection_schema_.GetRootName();
- if (root_name.empty()) {
- char buf[255];
- snprintf(buf, sizeof(buf), "ERROR: Unable to find root name in prebundled reflection schema\n");
- log::warn("{}", buf);
- return std::string(buf);
- }
-
- const reflection::Schema* schema = reflection_schema_.FindInReflectionSchema(root_name);
- if (schema == nullptr) {
- char buf[255];
- snprintf(buf, sizeof(buf), "ERROR: Unable to find schema root name:%s\n", root_name.c_str());
- log::warn("{}", buf);
- return std::string(buf);
- }
-
- flatbuffers::IDLOptions options{};
- options.output_default_scalars_in_json = true;
- flatbuffers::Parser parser{options};
- if (!parser.Deserialize(schema)) {
- char buf[255];
- snprintf(buf, sizeof(buf), "ERROR: Unable to deserialize bundle root name:%s\n",
- root_name.c_str());
- log::warn("{}", buf);
- return std::string(buf);
- }
-
- std::string jsongen;
- // GenerateText was renamed to GenText in 23.5.26 because the return behavior was changed.
- // https://github.com/google/flatbuffers/commit/950a71ab893e96147c30dd91735af6db73f72ae0
-#if FLATBUFFERS_VERSION_MAJOR < 23 || \
- (FLATBUFFERS_VERSION_MAJOR == 23 && \
- (FLATBUFFERS_VERSION_MINOR < 5 || \
- (FLATBUFFERS_VERSION_MINOR == 5 && FLATBUFFERS_VERSION_REVISION < 26)))
- flatbuffers::GenerateText(parser, dumpsys_data->data(), &jsongen);
-#else
- const char* error = flatbuffers::GenText(parser, dumpsys_data->data(), &jsongen);
- if (error != nullptr) {
- log::warn("{}", error);
- }
-#endif
- return jsongen;
-}
-
-void Dumpsys::impl::DumpWithArgsAsync(int fd, const char** /*args*/) const {
- const auto registry = dumpsys_module_.GetModuleRegistry();
- bluetooth::shim::GetController()->Dump(fd);
- bluetooth::shim::GetAclManager()->Dump(fd);
- bluetooth::shim::GetSnoopLogger()->DumpSnoozLogToFile();
-
- ModuleDumper dumper(fd, *registry, kDumpsysTitle);
- std::string dumpsys_data;
- std::ostringstream oss;
- dumper.DumpState(&dumpsys_data, oss);
-
- dprintf(fd, " ----- Filtering as Developer -----\n");
- FilterSchema(&dumpsys_data);
-
- dprintf(fd, "%s", PrintAsJson(&dumpsys_data).c_str());
-}
-
-void Dumpsys::impl::DumpWithArgsSync(int fd, const char** args, std::promise<void> promise) {
- if (bluetooth::shim::Stack::GetInstance()->LockForDumpsys([=, *this]() {
- log::info("Started dumpsys procedure");
- this->DumpWithArgsAsync(fd, args);
- })) {
- log::info("Successful dumpsys procedure");
- } else {
- log::info("Failed dumpsys procedure as stack was not longer active");
- }
- promise.set_value();
-}
-
-Dumpsys::Dumpsys(const std::string& pre_bundled_schema)
- : reflection_schema_(dumpsys::ReflectionSchema(pre_bundled_schema)) {}
-
-void Dumpsys::Dump(int fd, const char** args, std::promise<void> promise) {
- if (fd <= 0) {
- promise.set_value();
- return;
- }
- CallOn(pimpl_.get(), &Dumpsys::impl::DumpWithArgsSync, fd, args, std::move(promise));
-}
-
-/**
- * Module methods
- */
-void Dumpsys::ListDependencies(ModuleList* /* list */) const {}
-
-void Dumpsys::Start() { pimpl_ = std::make_unique<impl>(*this, reflection_schema_); }
-
-void Dumpsys::Stop() { pimpl_.reset(); }
-
-std::string Dumpsys::ToString() const { return kModuleName; }
-
-} // namespace shim
-} // namespace bluetooth
diff --git a/system/gd/shim/dumpsys.h b/system/gd/shim/dumpsys.h
deleted file mode 100644
index 95756cdfe9..0000000000
--- a/system/gd/shim/dumpsys.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2019 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 <future>
-#include <memory>
-#include <string>
-
-#include "dumpsys/reflection_schema.h"
-#include "module.h"
-
-namespace bluetooth {
-namespace shim {
-
-constexpr char kArgumentDeveloper[] = "--dev";
-
-class Dumpsys : public bluetooth::Module {
-public:
- void Dump(int fd, const char** args, std::promise<void> promise);
-
- Dumpsys(const std::string& pre_bundled_schema);
- Dumpsys(const Dumpsys&) = delete;
- Dumpsys& operator=(const Dumpsys&) = delete;
-
- ~Dumpsys() = default;
-
- static const ModuleFactory Factory;
-
-protected:
- void ListDependencies(ModuleList* list) const override; // Module
- void Start() override; // Module
- void Stop() override; // Module
- std::string ToString() const override; // Module
-
-private:
- struct impl;
- std::unique_ptr<impl> pimpl_;
- const dumpsys::ReflectionSchema reflection_schema_;
-};
-
-} // namespace shim
-} // namespace bluetooth
diff --git a/system/gd/shim/dumpsys_test.cc b/system/gd/shim/dumpsys_test.cc
deleted file mode 100644
index 8107f20a6c..0000000000
--- a/system/gd/shim/dumpsys_test.cc
+++ /dev/null
@@ -1,132 +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 "shim/dumpsys.h"
-
-#include <gtest/gtest.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <future>
-
-#include "module.h"
-#include "os/thread.h"
-#include "test_data/dumpsys_test_data_bin.h"
-
-namespace testing {
-
-using bluetooth::TestModuleRegistry;
-using namespace bluetooth;
-
-namespace {
-
-bool SimpleJsonValidator(int fd, int* dumpsys_byte_cnt) {
- char buf{0};
- bool within_double_quotes{false};
- int left_bracket{0}, right_bracket{0};
- while (read(fd, &buf, 1) != -1) {
- switch (buf) {
- (*dumpsys_byte_cnt)++;
- case '"':
- within_double_quotes = !within_double_quotes;
- break;
- case '{':
- if (!within_double_quotes) {
- left_bracket++;
- }
- break;
- case '}':
- if (!within_double_quotes) {
- right_bracket++;
- }
- break;
- default:
- break;
- }
- }
- return left_bracket == right_bracket;
-}
-
-} // namespace
-
-// To create dumpsys_test_header_bin.h:
-// make bluetooth_flatbuffer_bundler
-// ${ANDROID_BUILD_TOP}/out/host/linux-x86/bin/bluetooth_flatbuffer_bundler -w -m
-// bluetooth.DumpsysData -f test_gen/dumpsys_test_data_bin -n bluetooth::test test_gen/*
-
-class DumpsysTest : public Test {
-protected:
- void SetUp() override {
- dumpsys_module_ = new bluetooth::shim::Dumpsys(bluetooth::test::GetBundledSchemaData());
- fake_registry_.InjectTestModule(&shim::Dumpsys::Factory, dumpsys_module_);
- }
-
- void TearDown() override { fake_registry_.StopAll(); }
-
- int GetSocketBufferSize(int sockfd) {
- int socket_buffer_size;
- socklen_t optlen = sizeof(socket_buffer_size);
- getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&socket_buffer_size, &optlen);
- return socket_buffer_size;
- }
-
- void SetSocketBufferSize(int sockfd, int socket_buffer_size) {
- socklen_t optlen = sizeof(socket_buffer_size);
- ASSERT_EQ(0,
- setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (const void*)&socket_buffer_size, optlen));
- }
-
- TestModuleRegistry fake_registry_;
- os::Thread& thread_ = fake_registry_.GetTestThread();
- bluetooth::shim::Dumpsys* dumpsys_module_ = nullptr;
- os::Handler* client_handler_ = nullptr;
-};
-
-TEST_F(DumpsysTest, dump_as_developer) {
- const char* args[]{bluetooth::shim::kArgumentDeveloper, nullptr};
-
- int sv[2];
- ASSERT_EQ(0, socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, sv));
- int socket_buffer_size = GetSocketBufferSize(sv[0]);
-
- std::promise<void> promise;
- std::future future = promise.get_future();
- dumpsys_module_->Dump(sv[0], args, std::move(promise));
- future.wait();
-
- int dumpsys_byte_cnt = 0;
- ASSERT_TRUE(SimpleJsonValidator(sv[1], &dumpsys_byte_cnt));
- ASSERT_TRUE(dumpsys_byte_cnt < socket_buffer_size);
-}
-
-TEST_F(DumpsysTest, dump_as_user) {
- const char* args[]{"not-a-developer-option", nullptr};
-
- int sv[2];
- ASSERT_EQ(0, socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, sv));
- int socket_buffer_size = GetSocketBufferSize(sv[0]);
-
- std::promise<void> promise;
- std::future future = promise.get_future();
- dumpsys_module_->Dump(sv[0], args, std::move(promise));
- future.wait();
-
- int dumpsys_byte_cnt = 0;
- ASSERT_TRUE(SimpleJsonValidator(sv[1], &dumpsys_byte_cnt));
- ASSERT_TRUE(dumpsys_byte_cnt < socket_buffer_size);
-}
-
-} // namespace testing
diff --git a/system/gd/shim/test_data/dumpsys_data.bfbs b/system/gd/shim/test_data/dumpsys_data.bfbs
deleted file mode 100644
index afe2ea5407..0000000000
--- a/system/gd/shim/test_data/dumpsys_data.bfbs
+++ /dev/null
Binary files differ
diff --git a/system/gd/shim/test_data/dumpsys_test_data_bin b/system/gd/shim/test_data/dumpsys_test_data_bin
deleted file mode 100644
index b9c410d5c7..0000000000
--- a/system/gd/shim/test_data/dumpsys_test_data_bin
+++ /dev/null
Binary files differ
diff --git a/system/gd/shim/test_data/dumpsys_test_data_bin.h b/system/gd/shim/test_data/dumpsys_test_data_bin.h
deleted file mode 100644
index d1f118d0fa..0000000000
--- a/system/gd/shim/test_data/dumpsys_test_data_bin.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Generated file by bluetooth_flatbuffer bundler
-#pragma once
-#include <sys/types.h>
-
-#include <string>
-namespace bluetooth {
-namespace test {
-extern const unsigned char* data;
-extern const size_t data_size;
-const std::string& GetBundledSchemaData();
-} // namespace test
-} // namespace bluetooth
-const unsigned char data_[] = {
- 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c,
- 0x00, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x62,
- 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x73, 0x79,
- 0x73, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x42, 0x75, 0x6e,
- 0x64, 0x6c, 0x65, 0x64, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x73, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0xec, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x02, 0x00, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x42, 0x46, 0x42, 0x53, 0x10, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x08,
- 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 0x38, 0x01,
- 0x00, 0x00, 0x3c, 0xfe, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
- 0xf4, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f,
- 0x74, 0x68, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x73, 0x79, 0x73, 0x44, 0x61, 0x74, 0x61, 0x00,
- 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x0c,
- 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x82, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
- 0x00, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x74, 0x65, 0x73,
- 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x14, 0x00, 0x08,
- 0x00, 0x0c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x4c, 0x00, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x74, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x41, 0x6e, 0x79, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0x72, 0x69, 0x76,
- 0x61, 0x63, 0x79, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08,
- 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00,
- 0x00, 0x00, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x73, 0x79, 0x73, 0x5f,
- 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x08, 0x00, 0x0c, 0x00,
- 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x00, 0x00, 0xb6, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0d, 0x05, 0x00,
- 0x00, 0x00, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0x14,
- 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f,
- 0x74, 0x68, 0x2e, 0x73, 0x68, 0x69, 0x6d, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x73, 0x79, 0x73,
- 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x68,
- 0xff, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff,
- 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x41, 0x6e,
- 0x79, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x00, 0x46,
- 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x00, 0x74, 0x69, 0x74, 0x6c,
- 0x65, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c,
- 0x00, 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x62,
- 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
- 0x55, 0x6e, 0x69, 0x74, 0x54, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00,
- 0x00, 0x18, 0x00, 0x14, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08,
- 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x41, 0x6e, 0x79, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0x72, 0x69, 0x76, 0x61,
- 0x63, 0x79, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x00, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x00, 0x00,
- 0x00, 0x15, 0x00, 0x00, 0x00, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x2e,
- 0x44, 0x75, 0x6d, 0x70, 0x73, 0x79, 0x73, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00};
-const std::string string_data_(data_, data_ + sizeof(data_));
-const unsigned char* bluetooth::test::data = data_;
-const size_t bluetooth::test::data_size = 884;
-const std::string& bluetooth::test::GetBundledSchemaData() { return string_data_; }
diff --git a/system/gd/stack_manager.cc b/system/gd/stack_manager.cc
deleted file mode 100644
index 856d10a3c4..0000000000
--- a/system/gd/stack_manager.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2019 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_manager.h"
-
-#include <bluetooth/log.h>
-
-#include <chrono>
-#include <future>
-#include <queue>
-
-#include "common/bind.h"
-#include "module.h"
-#include "os/handler.h"
-#include "os/system_properties.h"
-#include "os/thread.h"
-#include "os/wakelock_manager.h"
-
-using ::bluetooth::os::Handler;
-using ::bluetooth::os::Thread;
-using ::bluetooth::os::WakelockManager;
-
-namespace bluetooth {
-
-void StackManager::StartUp(ModuleList* modules, Thread* stack_thread) {
- management_thread_ = new Thread("management_thread", Thread::Priority::NORMAL);
- handler_ = new Handler(management_thread_);
-
- WakelockManager::Get().Acquire();
-
- std::promise<void> promise;
- auto future = promise.get_future();
- handler_->Post(common::BindOnce(&StackManager::handle_start_up, common::Unretained(this), modules,
- stack_thread, std::move(promise)));
-
- auto init_status = future.wait_for(
- std::chrono::milliseconds(get_gd_stack_timeout_ms(/* is_start = */ true)));
-
- WakelockManager::Get().Release();
-
- log::info("init_status == {}", int(init_status));
-
- log::assert_that(init_status == std::future_status::ready, "Can't start stack, last instance: {}",
- registry_.last_instance_);
-
- log::info("init complete");
-}
-
-void StackManager::handle_start_up(ModuleList* modules, Thread* stack_thread,
- std::promise<void> promise) {
- registry_.Start(modules, stack_thread);
- promise.set_value();
-}
-
-void StackManager::ShutDown() {
- WakelockManager::Get().Acquire();
-
- std::promise<void> promise;
- auto future = promise.get_future();
- handler_->Post(common::BindOnce(&StackManager::handle_shut_down, common::Unretained(this),
- std::move(promise)));
-
- auto stop_status = future.wait_for(
- std::chrono::milliseconds(get_gd_stack_timeout_ms(/* is_start = */ false)));
-
- WakelockManager::Get().Release();
- WakelockManager::Get().CleanUp();
-
- log::assert_that(stop_status == std::future_status::ready, "Can't stop stack, last instance: {}",
- registry_.last_instance_);
-
- handler_->Clear();
- handler_->WaitUntilStopped(std::chrono::milliseconds(2000));
- delete handler_;
- delete management_thread_;
-}
-
-void StackManager::handle_shut_down(std::promise<void> promise) {
- registry_.StopAll();
- promise.set_value();
-}
-
-std::chrono::milliseconds StackManager::get_gd_stack_timeout_ms(bool is_start) {
- auto gd_timeout = os::GetSystemPropertyUint32(
- is_start ? "bluetooth.gd.start_timeout" : "bluetooth.gd.stop_timeout",
- /* default_value = */ is_start ? 3000 : 5000);
- return std::chrono::milliseconds(gd_timeout *
- os::GetSystemPropertyUint32("ro.hw_timeout_multiplier",
- /* default_value = */ 1));
-}
-
-} // namespace bluetooth
diff --git a/system/gd/stack_manager.h b/system/gd/stack_manager.h
deleted file mode 100644
index 892efc3c3b..0000000000
--- a/system/gd/stack_manager.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2019 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 "module.h"
-#include "os/handler.h"
-#include "os/thread.h"
-
-namespace bluetooth {
-
-class StackManager {
-public:
- void StartUp(ModuleList* modules, os::Thread* stack_thread);
- void ShutDown();
-
- template <class T>
- T* GetInstance() const {
- return static_cast<T*>(registry_.Get(&T::Factory));
- }
-
- template <class T>
- bool IsStarted() const {
- return registry_.IsStarted(&T::Factory);
- }
-
-private:
- os::Thread* management_thread_ = nullptr;
- os::Handler* handler_ = nullptr;
- ModuleRegistry registry_;
-
- void handle_start_up(ModuleList* modules, os::Thread* stack_thread, std::promise<void> promise);
- void handle_shut_down(std::promise<void> promise);
- static std::chrono::milliseconds get_gd_stack_timeout_ms(bool is_start);
-};
-
-} // namespace bluetooth
diff --git a/system/gd/stack_manager_unittest.cc b/system/gd/stack_manager_unittest.cc
deleted file mode 100644
index f3fb3b5c82..0000000000
--- a/system/gd/stack_manager_unittest.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2019 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_manager.h"
-
-#include "gtest/gtest.h"
-#include "os/thread.h"
-
-namespace bluetooth {
-namespace {
-
-TEST(StackManagerTest, DISABLED_start_and_shutdown_no_module) {
- StackManager stack_manager;
- ModuleList module_list;
- os::Thread thread{"test_thread", os::Thread::Priority::NORMAL};
- stack_manager.StartUp(&module_list, &thread);
- stack_manager.ShutDown();
-}
-
-class TestModuleNoDependency : public Module {
-public:
- static const ModuleFactory Factory;
-
-protected:
- void ListDependencies(ModuleList* /* list */) const {}
- void Start() override {}
- void Stop() override {}
- std::string ToString() const override { return std::string("TestModuleDep"); }
-};
-
-const ModuleFactory TestModuleNoDependency::Factory =
- ModuleFactory([]() { return new TestModuleNoDependency(); });
-
-TEST(StackManagerTest, DISABLED_get_module_instance) {
- StackManager stack_manager;
- ModuleList module_list;
- module_list.add<TestModuleNoDependency>();
- os::Thread thread{"test_thread", os::Thread::Priority::NORMAL};
- stack_manager.StartUp(&module_list, &thread);
- EXPECT_NE(stack_manager.GetInstance<TestModuleNoDependency>(), nullptr);
- stack_manager.ShutDown();
-}
-
-} // namespace
-} // namespace bluetooth
diff --git a/system/gd/storage/storage_module.cc b/system/gd/storage/storage_module.cc
index 7cdfd507da..ce5a89c6f7 100644
--- a/system/gd/storage/storage_module.cc
+++ b/system/gd/storage/storage_module.cc
@@ -178,10 +178,10 @@ void StorageModule::Start() {
// Cleanup temporary pairings if we have left guest mode
if (!com::android::bluetooth::flags::guest_mode_bond() && !is_restricted_mode_) {
- config->RemoveSectionWithProperty("Restricted");
+ pimpl_->cache_.RemoveSectionWithProperty("Restricted");
}
- config->FixDeviceTypeInconsistencies();
+ pimpl_->cache_.FixDeviceTypeInconsistencies();
if (bluetooth::os::ParameterProvider::GetBtKeystoreInterface() != nullptr) {
bluetooth::os::ParameterProvider::GetBtKeystoreInterface()
->ConvertEncryptOrDecryptKeyIfNeeded();
diff --git a/system/gd/storage/storage_module_test.cc b/system/gd/storage/storage_module_test.cc
index 07163922fe..2f600944ae 100644
--- a/system/gd/storage/storage_module_test.cc
+++ b/system/gd/storage/storage_module_test.cc
@@ -168,6 +168,7 @@ static const std::string kReadTestConfig =
"[01:02:03:ab:cd:ea]\n"
"Name = hello world\n"
"LinkKey = fedcba0987654321fedcba0987654328\n"
+ "DevType = 1\n"
"\n";
TEST_F(StorageModuleTest, read_existing_config_test) {
diff --git a/system/include/Android.bp b/system/include/Android.bp
index 5540d0dd45..2482effbf3 100644
--- a/system/include/Android.bp
+++ b/system/include/Android.bp
@@ -32,7 +32,6 @@ cc_library_headers {
visibility: [
"//packages/apps/Test/connectivity/sl4n",
"//packages/modules/Bluetooth:__subpackages__",
- "//vendor:__subpackages__",
],
header_libs: [
"aics_headers",
@@ -47,7 +46,6 @@ cc_library_headers {
"libbtcore_headers",
],
export_include_dirs: ["./"],
- vendor_available: true,
host_supported: true,
apex_available: [
"//apex_available:platform",
diff --git a/system/include/hardware/ble_scanner.h b/system/include/hardware/ble_scanner.h
index 67e0011987..6adb09d26c 100644
--- a/system/include/hardware/ble_scanner.h
+++ b/system/include/hardware/ble_scanner.h
@@ -28,30 +28,6 @@
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
-/** Callback invoked when batchscan reports are obtained */
-typedef void (*batchscan_reports_callback)(int client_if, int status, int report_format,
- int num_records, std::vector<uint8_t> data);
-
-/** Callback invoked when batchscan storage threshold limit is crossed */
-typedef void (*batchscan_threshold_callback)(int client_if);
-
-/** Track ADV VSE callback invoked when tracked device is found or lost */
-typedef void (*track_adv_event_callback)(btgatt_track_adv_info_t* p_track_adv_info);
-
-/** Callback for scan results */
-typedef void (*scan_result_callback)(uint16_t event_type, uint8_t addr_type, 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, std::vector<uint8_t> adv_data,
- RawAddress* original_bda);
-
-typedef struct {
- scan_result_callback scan_result_cb;
- batchscan_reports_callback batchscan_reports_cb;
- batchscan_threshold_callback batchscan_threshold_cb;
- track_adv_event_callback track_adv_event_cb;
-} btgatt_scanner_callbacks_t;
-
class AdvertisingTrackInfo {
public:
// For MSFT-based advertisement monitor.
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index 02a8f51778..a8a169a58d 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -238,6 +238,11 @@ typedef struct {
bool le_channel_sounding_supported;
} bt_local_le_features_t;
+typedef struct {
+ uint8_t number_of_supported_offloaded_le_coc_sockets;
+ uint8_t number_of_supported_offloaded_rfcomm_sockets;
+} bt_lpp_offload_features_t;
+
/** Bluetooth Vendor and Product ID info */
typedef struct {
uint8_t vendor_id_src;
@@ -415,6 +420,13 @@ typedef enum {
*/
BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE,
+ /**
+ * Description - Low power processor offload features
+ * Access mode - GET.
+ * Data Type - bt_lpp_offload_features_t.
+ */
+ BT_PROPERTY_LPP_OFFLOAD_FEATURES,
+
BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
} bt_property_type_t;
@@ -1010,6 +1022,8 @@ template <>
struct formatter<bt_bond_state_t> : enum_formatter<bt_bond_state_t> {};
template <>
struct formatter<bt_property_type_t> : enum_formatter<bt_property_type_t> {};
+template <>
+struct formatter<bt_ssp_variant_t> : enum_formatter<bt_ssp_variant_t> {};
} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_gatt.h b/system/include/hardware/bt_gatt.h
index 50096274e3..aa55e03701 100644
--- a/system/include/hardware/bt_gatt.h
+++ b/system/include/hardware/bt_gatt.h
@@ -37,9 +37,6 @@ typedef struct {
/** GATT Server callbacks */
const btgatt_server_callbacks_t* server;
-
- /** LE scanner callbacks */
- const btgatt_scanner_callbacks_t* scanner;
} btgatt_callbacks_t;
/** Represents the standard Bluetooth GATT interface. */
diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h
index 38f41ff44a..3de962b666 100644
--- a/system/include/hardware/bt_hh.h
+++ b/system/include/hardware/bt_hh.h
@@ -17,7 +17,6 @@
#ifndef ANDROID_INCLUDE_BT_HH_H
#define ANDROID_INCLUDE_BT_HH_H
-#include <base/strings/stringprintf.h>
#include <stdint.h>
#include <string>
@@ -51,7 +50,7 @@ inline std::string bthh_connection_state_text(const bthh_connection_state_t& sta
CASE_RETURN_TEXT(BTHH_CONN_STATE_ACCEPTING);
CASE_RETURN_TEXT(BTHH_CONN_STATE_UNKNOWN);
default:
- return base::StringPrintf("UNKNOWN[%d]", state);
+ return std::format("UNKNOWN[{}]", static_cast<int>(state));
}
}
diff --git a/system/include/hardware/bt_sock.h b/system/include/hardware/bt_sock.h
index c7fff44daf..0436fad9cb 100644
--- a/system/include/hardware/bt_sock.h
+++ b/system/include/hardware/bt_sock.h
@@ -38,6 +38,18 @@ typedef enum {
BTSOCK_L2CAP_LE = 4
} btsock_type_t;
+/**
+ * Data path used for Bluetooth socket communication.
+ *
+ * NOTE: The values must be same as:
+ * - BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD = 0
+ * - BluetoothSocketSettings.DATA_PATH_HARDWARE_OFFLOAD = 1
+ */
+typedef enum {
+ BTSOCK_DATA_PATH_NO_OFFLOAD = 0,
+ BTSOCK_DATA_PATH_HARDWARE_OFFLOAD = 1,
+} btsock_data_path_t;
+
/** Represents the standard BT SOCKET interface. */
typedef struct {
int16_t size;
@@ -56,9 +68,17 @@ typedef struct {
// The connection uuid. (L2CAP only)
uint64_t conn_uuid_lsb;
uint64_t conn_uuid_msb;
+
+ // Socket ID in connected state
+ uint64_t socket_id;
} __attribute__((packed)) sock_connect_signal_t;
typedef struct {
+ uint16_t size;
+ uint16_t is_accepting;
+} __attribute__((packed)) sock_accept_signal_t;
+
+typedef struct {
/** set to size of this struct*/
size_t size;
@@ -73,7 +93,8 @@ typedef struct {
*/
bt_status_t (*listen)(btsock_type_t type, const char* service_name,
const bluetooth::Uuid* service_uuid, int channel, int* sock_fd, int flags,
- int callingUid);
+ int callingUid, btsock_data_path_t data_path, const char* socket_name,
+ uint64_t hub_id, uint64_t endpoint_id, int max_rx_packet_size);
/**
* Connect to a RFCOMM UUID channel of remote device, It returns the socket fd
@@ -83,7 +104,9 @@ typedef struct {
* purposes.
*/
bt_status_t (*connect)(const RawAddress* bd_addr, btsock_type_t type, const bluetooth::Uuid* uuid,
- int channel, int* sock_fd, int flags, int callingUid);
+ int channel, int* sock_fd, int flags, int callingUid,
+ btsock_data_path_t data_path, const char* socket_name, uint64_t hub_id,
+ uint64_t endpoint_id, int max_rx_packet_size);
/**
* Set the LE Data Length value to this connected peer to the
@@ -128,6 +151,9 @@ __END_DECLS
namespace std {
template <>
struct formatter<btsock_type_t> : enum_formatter<btsock_type_t> {};
+
+template <>
+struct formatter<btsock_data_path_t> : enum_formatter<btsock_data_path_t> {};
} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/main/Android.bp b/system/main/Android.bp
index 5b270923f4..5272905831 100644
--- a/system/main/Android.bp
+++ b/system/main/Android.bp
@@ -41,10 +41,6 @@ cc_library_static {
"packages/modules/Bluetooth/system/udrv/include",
"system/security/keystore/include",
],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
apex_available: [
"com.android.btservices",
],
@@ -129,10 +125,6 @@ cc_library_static {
"packages/modules/Bluetooth/system/gd",
"packages/modules/Bluetooth/system/stack/include",
],
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
whole_static_libs: [
"libbluetooth_gd", // Gabeldorsche
],
@@ -191,13 +183,11 @@ cc_test {
"shim/stack.cc",
"shim/utils.cc",
"test/common_stack_test.cc",
- "test/main_shim_dumpsys_test.cc",
"test/main_shim_test.cc",
],
static_libs: [
"bluetooth_flags_c_lib_for_test",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-types",
"libbluetooth_core_rs_bridge",
"libbluetooth_crypto_toolbox",
@@ -236,10 +226,6 @@ cc_test {
undefined: true,
},
},
- generated_headers: [
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
min_sdk_version: "Tiramisu",
header_libs: ["libbluetooth_headers"],
}
diff --git a/system/main/shim/BUILD.gn b/system/main/shim/BUILD.gn
index 88bbba0c6b..ff7bdae78a 100644
--- a/system/main/shim/BUILD.gn
+++ b/system/main/shim/BUILD.gn
@@ -29,10 +29,9 @@ source_set("BluetoothStackManagerSources") {
]
deps = [
- "//bt/system/gd:BluetoothGeneratedDumpsysDataSchema_h",
"//bt/system/gd/common:BluetoothCommonSources",
- "//bt/system/gd/dumpsys/bundler:BluetoothGeneratedBundlerSchema_h_bfbs",
"//bt/system/gd/hci:BluetoothHciSources",
+ "//bt/system/gd/lpp:BluetoothLppOffloadSources",
"//bt/system/gd/os:BluetoothOsSources_linux_generic",
"//bt/system/gd/packet:BluetoothPacketSources",
"//bt/system/gd/rust/topshim:libbluetooth_topshim",
@@ -75,10 +74,9 @@ source_set("LibBluetoothShimSources") {
deps = [
"//bt/sysprop:libcom.android.sysprop.bluetooth",
- "//bt/system/gd:BluetoothGeneratedDumpsysDataSchema_h",
"//bt/system/gd/common:BluetoothCommonSources",
- "//bt/system/gd/dumpsys/bundler:BluetoothGeneratedBundlerSchema_h_bfbs",
"//bt/system/gd/hci:BluetoothHciSources",
+ "//bt/system/gd/lpp:BluetoothLppOffloadSources",
"//bt/system/gd/os:BluetoothOsSources_linux_generic",
"//bt/system/gd/packet:BluetoothPacketSources",
"//bt/system/gd/rust/topshim:libbluetooth_topshim",
diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc
index 7ab98517cb..d90e06a878 100644
--- a/system/main/shim/acl.cc
+++ b/system/main/shim/acl.cc
@@ -17,7 +17,6 @@
#include "main/shim/acl.h"
#include <base/location.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <time.h>
@@ -37,7 +36,6 @@
#include <vector>
#include "common/bind.h"
-#include "common/interfaces/ILoggable.h"
#include "common/strings.h"
#include "common/sync_map_count.h"
#include "hci/acl_manager.h"
@@ -77,7 +75,7 @@ extern tBTM_CB btm_cb;
using namespace bluetooth;
using ::bluetooth::os::WakelockManager;
-class ConnectAddressWithType : public bluetooth::common::IRedactableLoggable {
+class ConnectAddressWithType {
public:
explicit ConnectAddressWithType(hci::AddressWithType address_with_type)
: address_(address_with_type.GetAddress()),
@@ -90,8 +88,8 @@ public:
return ss.str();
}
- std::string ToStringForLogging() const override { return ToString(); }
- std::string ToRedactedStringForLogging() const override {
+ std::string ToStringForLogging() const { return ToString(); }
+ std::string ToRedactedStringForLogging() const {
std::stringstream ss;
ss << address_.ToRedactedStringForLogging() << "[" << FilterAcceptListAddressTypeText(type_)
<< "]";
@@ -204,56 +202,9 @@ std::string EpochMillisToString(long long time_ms) {
struct tm tm;
localtime_r(&time_sec, &tm);
std::string s = common::StringFormatTime(kConnectionDescriptorTimeFormat, tm);
- return base::StringPrintf("%s.%03u", s.c_str(),
- static_cast<unsigned int>(time_ms % MillisPerSecond));
+ return std::format("{}.{:03}", s, time_ms % MillisPerSecond);
}
-inline bool IsRpa(const hci::AddressWithType address_with_type) {
- return address_with_type.GetAddressType() == hci::AddressType::RANDOM_DEVICE_ADDRESS &&
- ((address_with_type.GetAddress().address.data()[5] & 0xc0) == 0x40);
-}
-
-class ShadowAcceptlist {
-public:
- explicit ShadowAcceptlist(uint8_t max_acceptlist_size)
- : max_acceptlist_size_(max_acceptlist_size) {}
-
- bool Add(const hci::AddressWithType& address_with_type) {
- if (acceptlist_set_.size() == max_acceptlist_size_) {
- log::error("Acceptlist is full size:{}", acceptlist_set_.size());
- return false;
- }
- if (!acceptlist_set_.insert(ConnectAddressWithType(address_with_type)).second) {
- log::warn("Attempted to add duplicate le address to acceptlist:{}", address_with_type);
- }
- return true;
- }
-
- bool Remove(const hci::AddressWithType& address_with_type) {
- auto iter = acceptlist_set_.find(ConnectAddressWithType(address_with_type));
- if (iter == acceptlist_set_.end()) {
- log::warn("Unknown device being removed from acceptlist:{}", address_with_type);
- return false;
- }
- acceptlist_set_.erase(ConnectAddressWithType(*iter));
- return true;
- }
-
- std::unordered_set<ConnectAddressWithType> GetCopy() const { return acceptlist_set_; }
-
- bool IsFull() const {
- return acceptlist_set_.size() == static_cast<size_t>(max_acceptlist_size_);
- }
-
- void Clear() { acceptlist_set_.clear(); }
-
- uint8_t GetMaxSize() const { return max_acceptlist_size_; }
-
-private:
- uint8_t max_acceptlist_size_{0};
- std::unordered_set<ConnectAddressWithType> acceptlist_set_;
-};
-
class ShadowAddressResolutionList {
public:
explicit ShadowAddressResolutionList(uint8_t max_address_resolution_size)
@@ -314,17 +265,15 @@ struct ConnectionDescriptor {
virtual std::string GetPrivateRemoteAddress() const = 0;
virtual ~ConnectionDescriptor() {}
std::string ToString() const {
- return base::StringPrintf(
- "peer:%s handle:0x%04x is_locally_initiated:%s"
- " creation_time:%s teardown_time:%s disconnect_reason:%s",
- GetPrivateRemoteAddress().c_str(), handle_, is_locally_initiated_ ? "true" : "false",
+ return std::format(
+ "peer:{} handle:0x{:04x} is_locally_initiated:{} creation_time:{} teardown_time:{} "
+ "disconnect_reason:{}",
+ GetPrivateRemoteAddress(), handle_, is_locally_initiated_,
common::StringFormatTimeWithMilliseconds(kConnectionDescriptorTimeFormat,
- creation_time_)
- .c_str(),
+ creation_time_),
common::StringFormatTimeWithMilliseconds(kConnectionDescriptorTimeFormat,
- teardown_time_)
- .c_str(),
- hci::ErrorCodeText(disconnect_reason_).c_str());
+ teardown_time_),
+ hci::ErrorCodeText(disconnect_reason_));
}
};
@@ -337,7 +286,7 @@ struct ClassicConnectionDescriptor : public ConnectionDescriptor {
disconnect_reason),
remote_address_(remote_address) {}
virtual std::string GetPrivateRemoteAddress() const {
- return ADDRESS_TO_LOGGABLE_CSTR(remote_address_);
+ return remote_address_.ToRedactedStringForLogging();
}
};
@@ -350,7 +299,7 @@ struct LeConnectionDescriptor : public ConnectionDescriptor {
disconnect_reason),
remote_address_with_type_(remote_address_with_type) {}
std::string GetPrivateRemoteAddress() const {
- return ADDRESS_TO_LOGGABLE_CSTR(remote_address_with_type_);
+ return remote_address_with_type_.ToRedactedStringForLogging();
}
};
@@ -658,10 +607,9 @@ public:
void OnRoleChange(hci::ErrorCode hci_status, hci::Role new_role) override {
TRY_POSTING_ON_MAIN(interface_.on_role_change, ToLegacyHciErrorCode(hci_status),
ToRawAddress(connection_->GetAddress()), ToLegacyRole(new_role));
- BTM_LogHistory(
- kBtmLogTag, ToRawAddress(connection_->GetAddress()), "Role change",
- base::StringPrintf("classic New_role:%s status:%s", hci::RoleText(new_role).c_str(),
- hci::ErrorCodeText(hci_status).c_str()));
+ BTM_LogHistory(kBtmLogTag, ToRawAddress(connection_->GetAddress()), "Role change",
+ std::format("classic New_role:{} status:{}", hci::RoleText(new_role),
+ hci::ErrorCodeText(hci_status)));
}
void OnDisconnection(hci::ErrorCode reason) override {
@@ -868,9 +816,8 @@ private:
};
struct shim::Acl::impl {
- impl(uint8_t max_acceptlist_size, uint8_t max_address_resolution_size)
- : shadow_acceptlist_(ShadowAcceptlist(max_acceptlist_size)),
- shadow_address_resolution_list_(ShadowAddressResolutionList(max_address_resolution_size)) {}
+ impl(uint8_t max_address_resolution_size)
+ : shadow_address_resolution_list_(ShadowAddressResolutionList(max_address_resolution_size)) {}
std::map<HciHandle, std::unique_ptr<ClassicShimAclConnection>> handle_to_classic_connection_map_;
std::map<HciHandle, std::unique_ptr<LeShimAclConnection>> handle_to_le_connection_map_;
@@ -881,7 +828,6 @@ struct shim::Acl::impl {
FixedQueue<std::unique_ptr<ConnectionDescriptor>> connection_history_ =
FixedQueue<std::unique_ptr<ConnectionDescriptor>>(kConnectionHistorySize);
- ShadowAcceptlist shadow_acceptlist_;
ShadowAddressResolutionList shadow_address_resolution_list_;
struct timed_wakelock wakeup_wakelock_;
@@ -1049,9 +995,9 @@ struct shim::Acl::impl {
auto remote_address = connection->second->GetRemoteAddress();
connection->second->InitiateDisconnect(ToDisconnectReasonFromLegacy(reason));
log::debug("Disconnection initiated classic remote:{} handle:{}", remote_address, handle);
- BTM_LogHistory(kBtmLogTag, ToRawAddress(remote_address), "Disconnection initiated",
- base::StringPrintf("classic reason:%s comment:%s",
- hci_status_code_text(reason).c_str(), comment.c_str()));
+ BTM_LogHistory(
+ kBtmLogTag, ToRawAddress(remote_address), "Disconnection initiated",
+ std::format("classic reason:{} comment:{}", hci_status_code_text(reason), comment));
classic_acl_disconnect_reason_.Put(comment);
} else {
log::warn("Unable to disconnect unknown classic connection handle:0x{:04x}", handle);
@@ -1068,8 +1014,7 @@ struct shim::Acl::impl {
handle);
BTM_LogHistory(kBtmLogTag, ToLegacyAddressWithType(remote_address_with_type),
"Disconnection initiated",
- base::StringPrintf("Le reason:%s comment:%s",
- hci_status_code_text(reason).c_str(), comment.c_str()));
+ std::format("Le reason:{} comment:{}", hci_status_code_text(reason), comment));
le_acl_disconnect_reason_.Put(comment);
} else {
log::warn("Unable to disconnect unknown le connection handle:0x{:04x}", handle);
@@ -1090,12 +1035,6 @@ struct shim::Acl::impl {
void accept_le_connection_from(const hci::AddressWithType& address_with_type, bool is_direct,
std::promise<bool> promise) {
- if (shadow_acceptlist_.IsFull()) {
- log::error("Acceptlist is full preventing new Le connection");
- promise.set_value(false);
- return;
- }
- shadow_acceptlist_.Add(address_with_type);
promise.set_value(true);
GetAclManager()->CreateLeConnection(address_with_type, is_direct);
log::debug("Allow Le connection from remote:{}", address_with_type);
@@ -1161,20 +1100,13 @@ struct shim::Acl::impl {
}
void ignore_le_connection_from(const hci::AddressWithType& address_with_type) {
- shadow_acceptlist_.Remove(address_with_type);
GetAclManager()->CancelLeConnect(address_with_type);
log::debug("Ignore Le connection from remote:{}", address_with_type);
BTM_LogHistory(kBtmLogTag, ToLegacyAddressWithType(address_with_type), "Ignore connection from",
"Le");
}
- void clear_acceptlist() {
- auto shadow_acceptlist = shadow_acceptlist_.GetCopy();
- size_t count = shadow_acceptlist.size();
- GetAclManager()->ClearFilterAcceptList();
- shadow_acceptlist_.Clear();
- log::debug("Cleared entire Le address acceptlist count:{}", count);
- }
+ void clear_acceptlist() { GetAclManager()->ClearFilterAcceptList(); }
void AddToAddressResolution(const hci::AddressWithType& address_with_type,
const std::array<uint8_t, 16>& peer_irk,
@@ -1210,12 +1142,6 @@ struct shim::Acl::impl {
for (auto& entry : history) {
log::debug("{}", entry);
}
- const auto acceptlist = shadow_acceptlist_.GetCopy();
- log::debug("Shadow le accept list size:{:<3} controller_max_size:{}", acceptlist.size(),
- shadow_acceptlist_.GetMaxSize());
- for (auto& entry : acceptlist) {
- log::debug("acceptlist:{}", entry);
- }
}
#define DUMPSYS_TAG "shim::acl"
@@ -1237,23 +1163,14 @@ struct shim::Acl::impl {
}
}
- auto acceptlist = shadow_acceptlist_.GetCopy();
- LOG_DUMPSYS(fd,
- "Shadow le accept list size:%-3zu "
- "controller_max_size:%hhu",
- acceptlist.size(), shadow_acceptlist_.GetMaxSize());
- unsigned cnt = 0;
- for (auto& entry : acceptlist) {
- LOG_DUMPSYS(fd, " %03u %s", ++cnt, ADDRESS_TO_LOGGABLE_CSTR(entry));
- }
auto address_resolution_list = shadow_address_resolution_list_.GetCopy();
LOG_DUMPSYS(fd,
"Shadow le address resolution list size:%-3zu "
"controller_max_size:%hhu",
address_resolution_list.size(), shadow_address_resolution_list_.GetMaxSize());
- cnt = 0;
+ unsigned cnt = 0;
for (auto& entry : address_resolution_list) {
- LOG_DUMPSYS(fd, " %03u %s", ++cnt, ADDRESS_TO_LOGGABLE_CSTR(entry));
+ LOG_DUMPSYS(fd, " %03u %s", ++cnt, entry.ToRedactedStringForLogging().c_str());
}
}
#undef DUMPSYS_TAG
@@ -1276,7 +1193,7 @@ void DumpsysAcl(int fd) {
}
LOG_DUMPSYS(fd, "remote_addr:%s handle:0x%04x transport:%s",
- ADDRESS_TO_LOGGABLE_CSTR(link.remote_addr), link.hci_handle,
+ link.remote_addr.ToRedactedStringForLogging().c_str(), link.hci_handle,
bt_transport_text(link.transport).c_str());
LOG_DUMPSYS(fd, " link_up_issued:%5s", (link.link_up_issued) ? "true" : "false");
LOG_DUMPSYS(fd, " flush_timeout:0x%04x", link.flush_timeout_in_ticks);
@@ -1307,7 +1224,7 @@ void DumpsysAcl(int fd) {
bd_features_text(link.peer_le_features).c_str());
LOG_DUMPSYS(fd, " [le] active_remote_addr:%s[%s]",
- ADDRESS_TO_LOGGABLE_CSTR(link.active_remote_addr),
+ link.active_remote_addr.ToRedactedStringForLogging().c_str(),
AddressTypeText(link.active_remote_addr_type).c_str());
}
}
@@ -1358,11 +1275,11 @@ void shim::Acl::Dump(int fd) const {
}
shim::Acl::Acl(os::Handler* handler, const acl_interface_t& acl_interface,
- uint8_t max_acceptlist_size, uint8_t max_address_resolution_size)
+ uint8_t max_address_resolution_size)
: handler_(handler), acl_interface_(acl_interface) {
log::assert_that(handler_ != nullptr, "assert failed: handler_ != nullptr");
ValidateAclInterface(acl_interface_);
- pimpl_ = std::make_unique<Acl::impl>(max_acceptlist_size, max_address_resolution_size);
+ pimpl_ = std::make_unique<Acl::impl>(max_address_resolution_size);
GetAclManager()->RegisterCallbacks(this, handler_);
GetAclManager()->RegisterLeCallbacks(this, handler_);
GetController()->RegisterCompletedMonitorAclPacketsCallback(
@@ -1473,7 +1390,7 @@ void shim::Acl::OnClassicLinkDisconnected(HciHandle handle, hci::ErrorCode reaso
log::debug("Disconnected classic link remote:{} handle:{} reason:{}", remote_address, handle,
ErrorCodeText(reason));
BTM_LogHistory(kBtmLogTag, ToRawAddress(remote_address), "Disconnected",
- base::StringPrintf("classic reason:%s", ErrorCodeText(reason).c_str()));
+ std::format("classic reason:{}", ErrorCodeText(reason)));
pimpl_->connection_history_.Push(std::make_unique<ClassicConnectionDescriptor>(
remote_address, creation_time, teardown_time, handle, is_locally_initiated, reason));
}
@@ -1514,7 +1431,7 @@ void shim::Acl::OnLeLinkDisconnected(HciHandle handle, hci::ErrorCode reason) {
log::debug("Disconnected le link remote:{} handle:{} reason:{}", remote_address_with_type, handle,
ErrorCodeText(reason));
BTM_LogHistory(kBtmLogTag, ToLegacyAddressWithType(remote_address_with_type), "Disconnected",
- base::StringPrintf("Le reason:%s", ErrorCodeText(reason).c_str()));
+ std::format("Le reason:{}", ErrorCodeText(reason)));
pimpl_->connection_history_.Push(std::make_unique<LeConnectionDescriptor>(
remote_address_with_type, creation_time, teardown_time, handle, is_locally_initiated,
reason));
@@ -1561,9 +1478,9 @@ void shim::Acl::OnConnectRequest(hci::Address address, hci::ClassOfDevice cod) {
TRY_POSTING_ON_MAIN(acl_interface_.connection.classic.on_connect_request, bd_addr, cod);
log::debug("Received connect request remote:{} gd_cod:{} legacy_dev_class:{}", address,
cod.ToString(), dev_class_text(dev_class));
- BTM_LogHistory(kBtmLogTag, ToRawAddress(address), "Connection request",
- base::StringPrintf("gd_cod:%s legacy_dev_class:%s", cod.ToString().c_str(),
- dev_class_text(dev_class).c_str()));
+ BTM_LogHistory(
+ kBtmLogTag, ToRawAddress(address), "Connection request",
+ std::format("gd_cod:{} legacy_dev_class:{}", cod.ToString(), dev_class_text(dev_class)));
}
void shim::Acl::OnConnectFail(hci::Address address, hci::ErrorCode reason, bool locally_initiated) {
@@ -1573,7 +1490,7 @@ void shim::Acl::OnConnectFail(hci::Address address, hci::ErrorCode reason, bool
log::warn("Connection failed classic remote:{} reason:{}", address, hci::ErrorCodeText(reason));
metrics::LogAclCompletionEvent(address, reason, locally_initiated);
BTM_LogHistory(kBtmLogTag, ToRawAddress(address), "Connection failed",
- base::StringPrintf("classic reason:%s", hci::ErrorCodeText(reason).c_str()));
+ std::format("classic reason:{}", hci::ErrorCodeText(reason)));
}
void shim::Acl::OnLeConnectSuccess(hci::AddressWithType address_with_type,
@@ -1625,18 +1542,6 @@ void shim::Acl::OnLeConnectSuccess(hci::AddressWithType address_with_type,
std::chrono::system_clock::now()));
pimpl_->handle_to_le_connection_map_[handle]->RegisterCallbacks();
- // Once an le connection has successfully been established
- // the device address is removed from the controller accept list.
-
- if (IsRpa(address_with_type)) {
- log::debug("Connection address is rpa:{} identity_addr:{}", address_with_type,
- peer_address_with_type);
- pimpl_->shadow_acceptlist_.Remove(peer_address_with_type);
- } else {
- log::debug("Connection address is not rpa addr:{}", address_with_type);
- pimpl_->shadow_acceptlist_.Remove(address_with_type);
- }
-
if (!pimpl_->handle_to_le_connection_map_[handle]->IsInFilterAcceptList() &&
connection_role == hci::Role::CENTRAL) {
pimpl_->handle_to_le_connection_map_[handle]->InitiateDisconnect(
@@ -1675,10 +1580,9 @@ void shim::Acl::OnLeConnectFail(hci::AddressWithType address_with_type, hci::Err
enhanced, status);
bluetooth::metrics::LogLeAclCompletionEvent(address_with_type.GetAddress(), reason, true);
- pimpl_->shadow_acceptlist_.Remove(address_with_type);
log::warn("Connection failed le remote:{}", address_with_type);
BTM_LogHistory(kBtmLogTag, ToLegacyAddressWithType(address_with_type), "Connection failed",
- base::StringPrintf("le reason:%s", hci::ErrorCodeText(reason).c_str()));
+ std::format("le reason:{}", hci::ErrorCodeText(reason)));
}
void shim::Acl::DisconnectClassic(uint16_t handle, tHCI_STATUS reason, std::string comment) {
diff --git a/system/main/shim/acl.h b/system/main/shim/acl.h
index 013660d7f4..ee73e006ea 100644
--- a/system/main/shim/acl.h
+++ b/system/main/shim/acl.h
@@ -37,7 +37,7 @@ class Acl : public hci::acl_manager::ConnectionCallbacks,
public hci::acl_manager::LeConnectionCallbacks,
public LinkConnectionInterface {
public:
- Acl(os::Handler* handler, const acl_interface_t& acl_interface, uint8_t max_acceptlist_size,
+ Acl(os::Handler* handler, const acl_interface_t& acl_interface,
uint8_t max_address_resolution_size);
Acl(const Acl&) = delete;
diff --git a/system/main/shim/acl_api.cc b/system/main/shim/acl_api.cc
index 90d9c7b9f5..08249592e7 100644
--- a/system/main/shim/acl_api.cc
+++ b/system/main/shim/acl_api.cc
@@ -111,7 +111,6 @@ void bluetooth::shim::ACL_ConfigureLePrivacy(bool is_le_privacy_enabled) {
android::sysprop::bluetooth::Ble::random_address_rotation_interval_max().value_or(15));
Stack::GetInstance()
- ->GetStackManager()
->GetInstance<bluetooth::hci::AclManager>()
->SetPrivacyPolicyForInitiatorAddress(address_policy, empty_address_with_type,
minimum_rotation_time, maximum_rotation_time);
diff --git a/system/main/shim/distance_measurement_manager.cc b/system/main/shim/distance_measurement_manager.cc
index 194eea195b..61150f3b07 100644
--- a/system/main/shim/distance_measurement_manager.cc
+++ b/system/main/shim/distance_measurement_manager.cc
@@ -202,6 +202,21 @@ public:
}
// Must be called from main_thread
+ // Callbacks of bluetooth::ras::RasServerCallbacks
+ void OnMtuChangedFromServer(const RawAddress& address, uint16_t mtu) override {
+ handle_mtu_changed(address, mtu);
+ }
+
+ void OnMtuChangedFromClient(const RawAddress& address, uint16_t mtu) override {
+ handle_mtu_changed(address, mtu);
+ }
+
+ void handle_mtu_changed(const RawAddress& address, uint16_t mtu) {
+ uint16_t connection_handle = GetConnectionHandleAndRole(address);
+ bluetooth::shim::GetDistanceMeasurementManager()->HandleMtuChanged(connection_handle, mtu);
+ }
+
+ // Must be called from main_thread
// Callbacks of bluetooth::ras::RasSeverCallbacks
void OnRasServerDisconnected(const RawAddress& identity_address) override {
bluetooth::shim::GetDistanceMeasurementManager()->HandleRasServerDisconnected(
diff --git a/system/main/shim/dumpsys.cc b/system/main/shim/dumpsys.cc
index 52e1a80850..77e45c17a1 100644
--- a/system/main/shim/dumpsys.cc
+++ b/system/main/shim/dumpsys.cc
@@ -25,7 +25,6 @@
#include "main/shim/entry.h"
#include "main/shim/shim.h"
#include "main/shim/stack.h"
-#include "shim/dumpsys.h"
namespace {
@@ -46,7 +45,7 @@ void bluetooth::shim::UnregisterDumpsysFunction(const void* token) {
dumpsys_functions_.erase(token);
}
-void bluetooth::shim::Dump(int fd, const char** args) {
+void bluetooth::shim::Dump(int fd) {
if (dumpsys_functions_.empty()) {
dprintf(fd, "%s No registered dumpsys shim legacy targets\n", kModuleName);
} else {
@@ -57,13 +56,7 @@ void bluetooth::shim::Dump(int fd, const char** args) {
}
std::promise<void> promise;
std::future future = promise.get_future();
- if (bluetooth::shim::Stack::GetInstance()->CallOnModule<shim::Dumpsys>(
- [&promise, fd, args](shim::Dumpsys* mod) {
- mod->Dump(fd, args, std::move(promise));
- })) {
- log::assert_that(future.wait_for(std::chrono::seconds(1)) == std::future_status::ready,
- "Timed out waiting for dumpsys to complete");
- } else {
- dprintf(fd, "%s NOTE: gd dumpsys module not loaded or started\n", kModuleName);
- }
+ bluetooth::shim::Stack::GetInstance()->Dump(fd, std::move(promise));
+ log::assert_that(future.wait_for(std::chrono::seconds(1)) == std::future_status::ready,
+ "Timed out waiting for dumpsys to complete");
}
diff --git a/system/main/shim/dumpsys.h b/system/main/shim/dumpsys.h
index 854609c735..746f9bd3df 100644
--- a/system/main/shim/dumpsys.h
+++ b/system/main/shim/dumpsys.h
@@ -48,7 +48,7 @@ using DumpsysFunction = std::function<void(int fd)>;
* Entrypoint from legacy stack to provide dumpsys functionality
* for both the legacy shim and the Gabeldorsche stack.
*/
-void Dump(int fd, const char** args);
+void Dump(int fd);
/**
* Dumpsys access for legacy shim modules.
diff --git a/system/main/shim/entry.cc b/system/main/shim/entry.cc
index a1c61b7ab0..ff0014b481 100644
--- a/system/main/shim/entry.cc
+++ b/system/main/shim/entry.cc
@@ -26,10 +26,10 @@
#include "hci/le_scanning_manager.h"
#include "hci/msft.h"
#include "hci/remote_name_request.h"
+#include "lpp/lpp_offload_manager.h"
#include "main/shim/stack.h"
#include "metrics/counter_metrics.h"
#include "os/handler.h"
-#include "shim/dumpsys.h"
#include "storage/storage_module.h"
namespace bluetooth {
@@ -38,49 +38,45 @@ namespace shim {
os::Handler* GetGdShimHandler() { return Stack::GetInstance()->GetHandler(); }
hci::LeAdvertisingManager* GetAdvertising() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::LeAdvertisingManager>();
+ return Stack::GetInstance()->GetInstance<hci::LeAdvertisingManager>();
}
hci::ControllerInterface* GetController() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::Controller>();
+ return Stack::GetInstance()->GetInstance<hci::Controller>();
}
-Dumpsys* GetDumpsys() { return Stack::GetInstance()->GetStackManager()->GetInstance<Dumpsys>(); }
-
-hci::HciInterface* GetHciLayer() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::HciLayer>();
-}
+hci::HciInterface* GetHciLayer() { return Stack::GetInstance()->GetInstance<hci::HciLayer>(); }
hci::RemoteNameRequestModule* GetRemoteNameRequest() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::RemoteNameRequestModule>();
+ return Stack::GetInstance()->GetInstance<hci::RemoteNameRequestModule>();
}
hci::LeScanningManager* GetScanning() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::LeScanningManager>();
+ return Stack::GetInstance()->GetInstance<hci::LeScanningManager>();
}
hci::DistanceMeasurementManager* GetDistanceMeasurementManager() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::DistanceMeasurementManager>();
+ return Stack::GetInstance()->GetInstance<hci::DistanceMeasurementManager>();
}
-hal::SnoopLogger* GetSnoopLogger() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hal::SnoopLogger>();
+hal::SnoopLogger* GetSnoopLogger() { return Stack::GetInstance()->GetInstance<hal::SnoopLogger>(); }
+
+lpp::LppOffloadInterface* GetLppOffloadManager() {
+ return Stack::GetInstance()->GetInstance<lpp::LppOffloadManager>();
}
storage::StorageModule* GetStorage() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<storage::StorageModule>();
+ return Stack::GetInstance()->GetInstance<storage::StorageModule>();
}
-hci::AclManager* GetAclManager() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::AclManager>();
-}
+hci::AclManager* GetAclManager() { return Stack::GetInstance()->GetInstance<hci::AclManager>(); }
metrics::CounterMetrics* GetCounterMetrics() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<metrics::CounterMetrics>();
+ return Stack::GetInstance()->GetInstance<metrics::CounterMetrics>();
}
hci::MsftExtensionManager* GetMsftExtensionManager() {
- return Stack::GetInstance()->GetStackManager()->GetInstance<hci::MsftExtensionManager>();
+ return Stack::GetInstance()->GetInstance<hci::MsftExtensionManager>();
}
} // namespace shim
diff --git a/system/main/shim/entry.h b/system/main/shim/entry.h
index e50cbc4d91..5202ecacb3 100644
--- a/system/main/shim/entry.h
+++ b/system/main/shim/entry.h
@@ -48,6 +48,10 @@ class LeScanningManager;
class MsftExtensionManager;
} // namespace hci
+namespace lpp {
+class LppOffloadInterface;
+}
+
namespace metrics {
class CounterMetrics;
}
@@ -57,18 +61,17 @@ class StorageModule;
}
namespace shim {
-class Dumpsys;
/* This returns a handler that might be used in shim to receive callbacks from
* within the stack. */
os::Handler* GetGdShimHandler();
hci::LeAdvertisingManager* GetAdvertising();
bluetooth::hci::ControllerInterface* GetController();
-Dumpsys* GetDumpsys();
hci::HciInterface* GetHciLayer();
hci::RemoteNameRequestModule* GetRemoteNameRequest();
hci::DistanceMeasurementManager* GetDistanceMeasurementManager();
hci::LeScanningManager* GetScanning();
+lpp::LppOffloadInterface* GetLppOffloadManager();
hal::SnoopLogger* GetSnoopLogger();
storage::StorageModule* GetStorage();
hci::AclManager* GetAclManager();
diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc
index e91f67d71f..6fcae663c0 100644
--- a/system/main/shim/le_advertising_manager.cc
+++ b/system/main/shim/le_advertising_manager.cc
@@ -86,7 +86,7 @@ public:
native_reg_id_map[client_id].erase(reg_id);
}
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert stopped",
- base::StringPrintf("advert_id:%d", advertiser_id));
+ std::format("advert_id:{}", advertiser_id));
}
// ::BleAdvertiserInterface
@@ -173,7 +173,7 @@ public:
log::info("create advertising set, client_id:{}, reg_id:{}", client_id, reg_id);
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le advert started",
- base::StringPrintf("reg_id:%d", reg_id));
+ std::format("reg_id:{}", reg_id));
return;
}
diff --git a/system/main/shim/le_scanning_manager.cc b/system/main/shim/le_scanning_manager.cc
index 6133da1797..8214dea25c 100644
--- a/system/main/shim/le_scanning_manager.cc
+++ b/system/main/shim/le_scanning_manager.cc
@@ -164,10 +164,10 @@ void BleScannerInterfaceImpl::Scan(bool start) {
// stopped
const uint64_t duration_timestamp =
timestamper_in_milliseconds.GetTimestamp() - btm_cb.neighbor.le_scan.start_time_ms;
- BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le scan stopped",
- base::StringPrintf("duration_s:%6.3f results:%-3lu",
- (double)duration_timestamp / 1000.0,
- (unsigned long)btm_cb.neighbor.le_scan.results));
+ BTM_LogHistory(
+ kBtmLogTag, RawAddress::kEmpty, "Le scan stopped",
+ std::format("duration_s:{:6.3f} results:{:<3}", (double)duration_timestamp / 1000.0,
+ btm_cb.neighbor.le_scan.results));
btm_cb.ble_ctr_cb.reset_ble_observe();
btm_cb.neighbor.le_scan = {};
} else {
diff --git a/system/main/shim/metrics_api.cc b/system/main/shim/metrics_api.cc
index 4ee87ce62d..65491b2468 100644
--- a/system/main/shim/metrics_api.cc
+++ b/system/main/shim/metrics_api.cc
@@ -16,7 +16,6 @@
#include "main/shim/metrics_api.h"
-#include "hci/address.h"
#include "main/shim/entry.h"
#include "main/shim/helpers.h"
#include "metrics/bluetooth_event.h"
@@ -156,6 +155,33 @@ void LogMetricLePairingFail(const RawAddress& raw_address, uint8_t failure_reaso
bluetooth::metrics::LogLePairingFail(raw_address, failure_reason, is_outgoing);
}
+void LogMetricLeConnectionStatus(hci::Address address, bool is_connect, hci::ErrorCode reason) {
+ bluetooth::os::LogMetricBluetoothEvent(
+ address,
+ is_connect ? android::bluetooth::EventType::GATT_CONNECT_NATIVE
+ : android::bluetooth::EventType::GATT_DISCONNECT_NATIVE,
+ bluetooth::metrics::MapErrorCodeToState(reason));
+}
+
+void LogMetricLeDeviceInAcceptList(hci::Address address, bool is_add) {
+ bluetooth::os::LogMetricBluetoothEvent(
+ address, android::bluetooth::EventType::LE_DEVICE_IN_ACCEPT_LIST,
+ is_add ? android::bluetooth::State::START : android::bluetooth::State::END);
+}
+
+void LogMetricLeConnectionLifecycle(hci::Address address, bool is_connect, bool is_direct) {
+ if (is_connect) {
+ bluetooth::os::LogMetricBluetoothEvent(address,
+ android::bluetooth::EventType::GATT_CONNECT_NATIVE,
+ is_direct ? android::bluetooth::State::DIRECT_CONNECT
+ : android::bluetooth::State::INDIRECT_CONNECT);
+ } else {
+ bluetooth::os::LogMetricBluetoothEvent(address,
+ android::bluetooth::EventType::GATT_DISCONNECT_NATIVE,
+ android::bluetooth::State::START);
+ }
+}
+
bool CountCounterMetrics(int32_t key, int64_t count) {
auto counter_metrics = GetCounterMetrics();
if (counter_metrics == nullptr) {
diff --git a/system/main/shim/metrics_api.h b/system/main/shim/metrics_api.h
index c030d7cc57..c0165b04b6 100644
--- a/system/main/shim/metrics_api.h
+++ b/system/main/shim/metrics_api.h
@@ -20,6 +20,8 @@
#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h>
+#include "hci/address.h"
+#include "hci/hci_packets.h"
#include "os/metrics.h"
#include "types/raw_address.h"
@@ -256,6 +258,29 @@ void LogMetricManufacturerInfo(const RawAddress& address,
void LogMetricLePairingFail(const RawAddress& raw_address, uint8_t failure_reason,
bool is_outgoing);
+/**
+ * Logs GATT connect/disconnect status
+ * @param address Address of the device
+ * @param is_connect indicates connection or disconnection
+ * @param reason the reason/status for the connection event
+ */
+void LogMetricLeConnectionStatus(hci::Address address, bool is_connect, hci::ErrorCode reason);
+
+/**
+ * Logs LE filter accept list events
+ * @param address Address of the device
+ * @param is_add indicates addition or removal of the device in the accept list
+ */
+void LogMetricLeDeviceInAcceptList(hci::Address address, bool is_connect);
+
+/**
+ * Logs GATT lifecycle events
+ * @param address Address of the device
+ * @param is_connect indicates connection or disconnection
+ * @param is_direct indicates direct or background connection, ignored for disconnection
+ */
+void LogMetricLeConnectionLifecycle(hci::Address address, bool is_connect, bool is_direct);
+
bool CountCounterMetrics(int32_t key, int64_t count);
} // namespace shim
diff --git a/system/main/shim/stack.cc b/system/main/shim/stack.cc
index 73526bc4dd..6da9117ae4 100644
--- a/system/main/shim/stack.cc
+++ b/system/main/shim/stack.cc
@@ -19,13 +19,18 @@
#include "main/shim/stack.h"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <fcntl.h>
#include <unistd.h>
+#include <chrono>
+#include <future>
+#include <queue>
#include <string>
#include "common/strings.h"
#include "hal/hci_hal.h"
+#include "hal/snoop_logger.h"
#include "hci/acl_manager.h"
#include "hci/acl_manager/acl_scheduler.h"
#include "hci/controller.h"
@@ -36,6 +41,7 @@
#include "hci/le_scanning_manager.h"
#include "hci/msft.h"
#include "hci/remote_name_request.h"
+#include "lpp/lpp_offload_manager.h"
#include "main/shim/acl.h"
#include "main/shim/acl_interface.h"
#include "main/shim/distance_measurement_manager.h"
@@ -44,17 +50,21 @@
#include "main/shim/le_advertising_manager.h"
#include "main/shim/le_scanning_manager.h"
#include "metrics/counter_metrics.h"
-#include "shim/dumpsys.h"
+#include "os/system_properties.h"
+#include "os/wakelock_manager.h"
#include "storage/storage_module.h"
+
#if TARGET_FLOSS
#include "sysprops/sysprops_module.h"
#endif
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+using ::bluetooth::os::WakelockManager;
+
namespace bluetooth {
namespace shim {
-using ::bluetooth::common::StringFormat;
-
struct Stack::impl {
Acl* acl_ = nullptr;
};
@@ -74,12 +84,15 @@ void Stack::StartEverything() {
#if TARGET_FLOSS
modules.add<sysprops::SyspropsModule>();
+#else
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3286716
+ modules.add<lpp::LppOffloadManager>();
+ }
#endif
modules.add<metrics::CounterMetrics>();
modules.add<hal::HciHal>();
modules.add<hci::HciLayer>();
modules.add<storage::StorageModule>();
- modules.add<shim::Dumpsys>();
modules.add<hci::Controller>();
modules.add<hci::acl_manager::AclScheduler>();
@@ -89,18 +102,21 @@ void Stack::StartEverything() {
modules.add<hci::MsftExtensionManager>();
modules.add<hci::LeScanningManager>();
modules.add<hci::DistanceMeasurementManager>();
- Start(&modules);
+
+ stack_thread_ = new os::Thread("gd_stack_thread", os::Thread::Priority::REAL_TIME);
+ StartUp(&modules, stack_thread_);
+
+ stack_handler_ = new os::Handler(stack_thread_);
+
+ log::info("Successfully toggled Gd stack");
+
is_running_ = true;
// Make sure the leaf modules are started
- log::assert_that(stack_manager_.GetInstance<storage::StorageModule>() != nullptr,
- "assert failed: stack_manager_.GetInstance<storage::StorageModule>() != "
- "nullptr");
- log::assert_that(stack_manager_.GetInstance<shim::Dumpsys>() != nullptr,
- "assert failed: stack_manager_.GetInstance<shim::Dumpsys>() != nullptr");
- if (stack_manager_.IsStarted<hci::Controller>()) {
+ log::assert_that(GetInstance<storage::StorageModule>() != nullptr,
+ "assert failed: GetInstance<storage::StorageModule>() != nullptr");
+ if (IsStarted<hci::Controller>()) {
pimpl_->acl_ =
- new Acl(stack_handler_, GetAclInterface(), GetController()->GetLeFilterAcceptListSize(),
- GetController()->GetLeResolvingListSize());
+ new Acl(stack_handler_, GetAclInterface(), GetController()->GetLeResolvingListSize());
} else {
log::error("Unable to create shim ACL layer as Controller has not started");
}
@@ -117,25 +133,13 @@ void Stack::StartModuleStack(const ModuleList* modules, const os::Thread* thread
stack_thread_ = const_cast<os::Thread*>(thread);
log::info("Starting Gd stack");
- stack_manager_.StartUp(const_cast<ModuleList*>(modules), stack_thread_);
+ StartUp(const_cast<ModuleList*>(modules), stack_thread_);
stack_handler_ = new os::Handler(stack_thread_);
num_modules_ = modules->NumModules();
is_running_ = true;
}
-void Stack::Start(ModuleList* modules) {
- log::assert_that(!is_running_, "Gd stack already running");
- log::info("Starting Gd stack");
-
- stack_thread_ = new os::Thread("gd_stack_thread", os::Thread::Priority::REAL_TIME);
- stack_manager_.StartUp(modules, stack_thread_);
-
- stack_handler_ = new os::Handler(stack_thread_);
-
- log::info("Successfully toggled Gd stack");
-}
-
void Stack::Stop() {
std::lock_guard<std::recursive_mutex> lock(mutex_);
bluetooth::shim::hci_on_shutting_down();
@@ -152,7 +156,26 @@ void Stack::Stop() {
stack_handler_->Clear();
- stack_manager_.ShutDown();
+ WakelockManager::Get().Acquire();
+
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ management_handler_->Post(
+ common::BindOnce(&Stack::handle_shut_down, common::Unretained(this), std::move(promise)));
+
+ auto stop_status = future.wait_for(
+ std::chrono::milliseconds(get_gd_stack_timeout_ms(/* is_start = */ false)));
+
+ WakelockManager::Get().Release();
+ WakelockManager::Get().CleanUp();
+
+ log::assert_that(stop_status == std::future_status::ready, "Can't stop stack, last instance: {}",
+ registry_.last_instance_);
+
+ management_handler_->Clear();
+ management_handler_->WaitUntilStopped(std::chrono::milliseconds(2000));
+ delete management_handler_;
+ delete management_thread_;
delete stack_handler_;
stack_handler_ = nullptr;
@@ -169,18 +192,6 @@ bool Stack::IsRunning() {
return is_running_;
}
-StackManager* Stack::GetStackManager() {
- std::lock_guard<std::recursive_mutex> lock(mutex_);
- log::assert_that(is_running_, "assert failed: is_running_");
- return &stack_manager_;
-}
-
-const StackManager* Stack::GetStackManager() const {
- std::lock_guard<std::recursive_mutex> lock(mutex_);
- log::assert_that(is_running_, "assert failed: is_running_");
- return &stack_manager_;
-}
-
Acl* Stack::GetAcl() {
std::lock_guard<std::recursive_mutex> lock(mutex_);
log::assert_that(is_running_, "assert failed: is_running_");
@@ -194,17 +205,64 @@ os::Handler* Stack::GetHandler() {
return stack_handler_;
}
-bool Stack::IsDumpsysModuleStarted() const {
+void Stack::Dump(int fd, std::promise<void> promise) const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
- return GetStackManager()->IsStarted<Dumpsys>();
+ if (is_running_ && fd >= 0) {
+ stack_handler_->Call(
+ [](int fd, std::promise<void> promise) {
+ bluetooth::shim::GetController()->Dump(fd);
+ bluetooth::shim::GetAclManager()->Dump(fd);
+ bluetooth::os::WakelockManager::Get().Dump(fd);
+ bluetooth::shim::GetSnoopLogger()->DumpSnoozLogToFile();
+ promise.set_value();
+ },
+ fd, std::move(promise));
+ } else {
+ promise.set_value();
+ }
}
-bool Stack::LockForDumpsys(std::function<void()> dumpsys_callback) {
- std::lock_guard<std::recursive_mutex> lock(mutex_);
- if (is_running_) {
- dumpsys_callback();
- }
- return is_running_;
+void Stack::StartUp(ModuleList* modules, Thread* stack_thread) {
+ management_thread_ = new Thread("management_thread", Thread::Priority::NORMAL);
+ management_handler_ = new Handler(management_thread_);
+
+ WakelockManager::Get().Acquire();
+
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ management_handler_->Post(common::BindOnce(&Stack::handle_start_up, common::Unretained(this),
+ modules, stack_thread, std::move(promise)));
+
+ auto init_status = future.wait_for(
+ std::chrono::milliseconds(get_gd_stack_timeout_ms(/* is_start = */ true)));
+
+ WakelockManager::Get().Release();
+
+ log::info("init_status == {}", int(init_status));
+
+ log::assert_that(init_status == std::future_status::ready, "Can't start stack, last instance: {}",
+ registry_.last_instance_);
+
+ log::info("init complete");
+}
+
+void Stack::handle_start_up(ModuleList* modules, Thread* stack_thread, std::promise<void> promise) {
+ registry_.Start(modules, stack_thread);
+ promise.set_value();
+}
+
+void Stack::handle_shut_down(std::promise<void> promise) {
+ registry_.StopAll();
+ promise.set_value();
+}
+
+std::chrono::milliseconds Stack::get_gd_stack_timeout_ms(bool is_start) {
+ auto gd_timeout = os::GetSystemPropertyUint32(
+ is_start ? "bluetooth.gd.start_timeout" : "bluetooth.gd.stop_timeout",
+ /* default_value = */ is_start ? 3000 : 5000);
+ return std::chrono::milliseconds(gd_timeout *
+ os::GetSystemPropertyUint32("ro.hw_timeout_multiplier",
+ /* default_value = */ 1));
}
} // namespace shim
diff --git a/system/main/shim/stack.h b/system/main/shim/stack.h
index 0fd99aa6c2..0dfd3fe3ab 100644
--- a/system/main/shim/stack.h
+++ b/system/main/shim/stack.h
@@ -22,7 +22,6 @@
#include "module.h"
#include "os/handler.h"
#include "os/thread.h"
-#include "stack_manager.h"
// The shim layer implementation on the Gd stack side.
namespace bluetooth {
@@ -47,30 +46,26 @@ public:
void Stop();
bool IsRunning();
- bool IsDumpsysModuleStarted() const;
- StackManager* GetStackManager();
- const StackManager* GetStackManager() const;
+ template <class T>
+ T* GetInstance() const {
+ return static_cast<T*>(registry_.Get(&T::Factory));
+ }
+
+ template <class T>
+ bool IsStarted() const {
+ return registry_.IsStarted(&T::Factory);
+ }
Acl* GetAcl();
os::Handler* GetHandler();
- bool LockForDumpsys(std::function<void()> dumpsys_callback);
+ void Dump(int fd, std::promise<void> promise) const;
// Start the list of modules with the given stack manager thread
void StartModuleStack(const ModuleList* modules, const os::Thread* thread);
- // Run the callable object on the module instance
- template <typename T>
- bool CallOnModule(std::function<void(T* mod)> run) {
- std::lock_guard<std::recursive_mutex> lock(mutex_);
- if (is_running_) {
- run(stack_manager_.GetInstance<T>());
- }
- return is_running_;
- }
-
size_t NumModules() const { return num_modules_; }
private:
@@ -78,12 +73,20 @@ private:
std::shared_ptr<impl> pimpl_;
mutable std::recursive_mutex mutex_;
- StackManager stack_manager_;
bool is_running_ = false;
os::Thread* stack_thread_ = nullptr;
os::Handler* stack_handler_ = nullptr;
size_t num_modules_{0};
- void Start(ModuleList* modules);
+
+ void StartUp(ModuleList* modules, os::Thread* stack_thread);
+
+ os::Thread* management_thread_ = nullptr;
+ os::Handler* management_handler_ = nullptr;
+ ModuleRegistry registry_;
+
+ void handle_start_up(ModuleList* modules, os::Thread* stack_thread, std::promise<void> promise);
+ void handle_shut_down(std::promise<void> promise);
+ static std::chrono::milliseconds get_gd_stack_timeout_ms(bool is_start);
};
} // namespace shim
diff --git a/system/main/test/main_shim_dumpsys_test.cc b/system/main/test/main_shim_dumpsys_test.cc
deleted file mode 100644
index a61a55cda5..0000000000
--- a/system/main/test/main_shim_dumpsys_test.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2022 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 <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-
-#include <future>
-
-#include "module.h"
-#include "os/handler.h"
-#include "os/system_properties.h"
-#include "os/thread.h"
-#include "shim/dumpsys.h"
-#include "stack_manager.h"
-
-using namespace bluetooth;
-using namespace testing;
-
-namespace {
-
-constexpr char kTrue[] = "1";
-constexpr char kFalse[] = "0";
-constexpr char kReadOnlyDebuggableProperty[] = "ro.debuggable";
-
-} // namespace
-
-class MainShimDumpsysTest : public testing::Test {
-public:
-protected:
- void SetUp() override {
- ModuleList modules;
- modules.add<shim::Dumpsys>();
-
- os::Thread* thread = new os::Thread("thread", os::Thread::Priority::NORMAL);
- stack_manager_.StartUp(&modules, thread);
- }
- void TearDown() override { stack_manager_.ShutDown(); }
- StackManager stack_manager_;
-
- os::Thread* thread_{nullptr};
- os::Handler* handler_{nullptr};
-};
-
-TEST_F(MainShimDumpsysTest, dumpsys_developer) {
- ASSERT_TRUE(os::SetSystemProperty(kReadOnlyDebuggableProperty, kTrue));
-
- std::promise<void> promise;
- auto future = promise.get_future();
- stack_manager_.GetInstance<shim::Dumpsys>()->Dump(STDOUT_FILENO, nullptr, std::move(promise));
- future.get();
-}
-
-TEST_F(MainShimDumpsysTest, dumpsys_user) {
- ASSERT_TRUE(os::SetSystemProperty(kReadOnlyDebuggableProperty, kFalse));
-
- std::promise<void> promise;
- auto future = promise.get_future();
- stack_manager_.GetInstance<shim::Dumpsys>()->Dump(STDOUT_FILENO, nullptr, std::move(promise));
- future.get();
-}
diff --git a/system/main/test/main_shim_test.cc b/system/main/test/main_shim_test.cc
index f5ca4026a2..9de16ba92b 100644
--- a/system/main/test/main_shim_test.cc
+++ b/system/main/test/main_shim_test.cc
@@ -80,8 +80,7 @@ using HciHandle = uint16_t;
namespace test = bluetooth::hci::testing;
-const uint8_t kMaxLeAcceptlistSize = 16;
-const uint8_t kMaxAddressResolutionSize = kMaxLeAcceptlistSize;
+const uint8_t kMaxAddressResolutionSize = 16;
tL2C_CB l2cb;
tBTM_CB btm_cb;
@@ -379,8 +378,7 @@ protected:
EXPECT_CALL(*test::mock_acl_manager_, RegisterLeCallbacks(_, _)).Times(1);
EXPECT_CALL(*test::mock_controller_, RegisterCompletedMonitorAclPacketsCallback(_)).Times(1);
EXPECT_CALL(*test::mock_controller_, UnregisterCompletedMonitorAclPacketsCallback).Times(1);
- return std::make_unique<shim::Acl>(handler_, GetMockAclInterface(), kMaxLeAcceptlistSize,
- kMaxAddressResolutionSize);
+ return std::make_unique<shim::Acl>(handler_, GetMockAclInterface(), kMaxAddressResolutionSize);
}
};
diff --git a/system/osi/src/stack_power_telemetry.cc b/system/osi/src/stack_power_telemetry.cc
index 262bb2afb2..18199bcd18 100644
--- a/system/osi/src/stack_power_telemetry.cc
+++ b/system/osi/src/stack_power_telemetry.cc
@@ -750,7 +750,7 @@ void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) {
const RawAddress& bd_addr = itr.first;
std::list<ChannelDetails> channel_details_list = itr.second;
for (auto& channel_details : channel_details_list) {
- dprintf(fd, "%-19s ", ADDRESS_TO_LOGGABLE_CSTR(bd_addr));
+ dprintf(fd, "%-19s ", bd_addr.ToRedactedStringForLogging().c_str());
dprintf(fd, "%-7s %-7d %-7d %-8d %-22s %-22s %-14s",
(channel_details.channel_type == ChannelType::kRfcomm) ? "RFCOMM" : "L2CAP",
channel_details.src.cid, channel_details.dst.cid, channel_details.psm,
@@ -799,7 +799,7 @@ void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) {
uint16_t handle = itr.first;
SniffData sniff_data = itr.second;
dprintf(fd, "%-8d %-19s %-19d %-24ld %-19d %-24ld\n", handle,
- ADDRESS_TO_LOGGABLE_CSTR(sniff_data.bd_addr), sniff_data.active_count,
+ sniff_data.bd_addr.ToRedactedStringForLogging().c_str(), sniff_data.active_count,
(long)sniff_data.active_duration_ts, sniff_data.sniff_count,
(long)sniff_data.sniff_duration_ts);
}
@@ -812,13 +812,15 @@ void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) {
for (auto it : ldc.acl.link_details_map) {
uint16_t handle = it.first;
LinkDetails lds = it.second;
- dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", handle, ADDRESS_TO_LOGGABLE_CSTR(lds.bd_addr),
+ dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", handle,
+ lds.bd_addr.ToRedactedStringForLogging().c_str(),
GetTimeString(lds.duration.begin).c_str(), GetTimeString(lds.duration.end).c_str(),
lds.tx_power_level);
}
for (auto& it : ldc.acl.link_details_list) {
- dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", it.handle, ADDRESS_TO_LOGGABLE_CSTR(it.bd_addr),
+ dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", it.handle,
+ it.bd_addr.ToRedactedStringForLogging().c_str(),
GetTimeString(it.duration.begin).c_str(), GetTimeString(it.duration.end).c_str(),
it.tx_power_level);
}
@@ -828,7 +830,8 @@ void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) {
"DisconnectedTimeStamp");
for (auto&& ldc : pimpl_->log_data_containers_) {
for (auto& it : ldc.sco.link_details_list) {
- dprintf(fd, "%-6d %-19s %-22s %-22s\n", it.handle, ADDRESS_TO_LOGGABLE_CSTR(it.bd_addr),
+ dprintf(fd, "%-6d %-19s %-22s %-22s\n", it.handle,
+ it.bd_addr.ToRedactedStringForLogging().c_str(),
GetTimeString(it.duration.begin).c_str(), GetTimeString(it.duration.end).c_str());
}
}
diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl
index ab1e390c42..3810ffefd0 100644
--- a/system/pdl/hci/hci_packets.pdl
+++ b/system/pdl/hci/hci_packets.pdl
@@ -4917,7 +4917,6 @@ packet LeSubrateRequestStatus : CommandStatus (command_op_code = LE_SUBRATE_REQU
}
packet LeCsReadLocalSupportedCapabilities : DistanceMeasurementCommand (op_code = LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES) {
-
}
struct CsRoleSupported {
@@ -4954,7 +4953,7 @@ struct CsOptionalCsSyncPhysSupported {
}
struct CsOptionalSubfeaturesSupported {
- companion_signal : 1,
+ _reserved_ : 1,
frequency_actuation_error : 1,
channel_selection_algorithm : 1,
phase_based_ranging : 1,
@@ -5140,7 +5139,7 @@ enum CsRole : 8 {
}
enum CsConfigRttType : 8 {
- RTT_AA_COARSE = 0x00,
+ RTT_AA_ONLY = 0x00,
RTT_WITH_32_BIT_SOUNDING_SEQUENCE = 0x01,
RTT_WITH_96_BIT_SOUNDING_SEQUENCE = 0x02,
RTT_WITH_32_BIT_RANDOM_SEQUENCE = 0x03,
@@ -5293,7 +5292,7 @@ packet LeCsTest : DistanceMeasurementCommand (op_code = LE_CS_TEST) {
snr_control_reflector: CsSnrControl,
drbg_nonce : 16,
channel_map_repetition : 8,
- override_config : 8,
+ override_config : 16,
override_parameters_length : 8,
override_parameters_data : 8[],
}
@@ -6890,6 +6889,7 @@ packet LeCsProcedureEnableComplete : LeMetaEvent (subevent_code = LE_CS_PROCEDUR
event_interval : 16,
procedure_interval : 16,
procedure_count : 16,
+ max_procedure_len : 16,
}
struct LeCsMode0InitatorData {
@@ -6975,8 +6975,8 @@ struct LeCsMode3InitatorData {
packet_quality : 8,
packet_nadm : CsPacketNadm,
packet_rssi : 8,
- packet_antenna : 8,
toa_tod_initiator : 16,
+ packet_antenna : 8,
antenna_permutation_index : 8,
tone_data : LeCsToneDataWithQuality[],
}
@@ -6986,10 +6986,10 @@ struct LeCsMode3InitatorDataWithPacketPct {
packet_quality : 8,
packet_nadm : CsPacketNadm,
packet_rssi : 8,
+ toa_tod_initiator : 16,
packet_antenna : 8,
packet_pct1 : LeCsToneData,
packet_pct2 : LeCsToneData,
- toa_tod_initiator : 16,
antenna_permutation_index : 8,
tone_data : LeCsToneDataWithQuality[],
}
@@ -6999,8 +6999,8 @@ struct LeCsMode3ReflectorData {
packet_quality : 8,
packet_nadm : CsPacketNadm,
packet_rssi : 8,
- packet_antenna : 8,
tod_toa_reflector : 16,
+ packet_antenna : 8,
antenna_permutation_index : 8,
tone_data : LeCsToneDataWithQuality[],
}
@@ -7010,10 +7010,10 @@ struct LeCsMode3ReflectorDataWithPacketPct {
packet_quality : 8,
packet_nadm : CsPacketNadm,
packet_rssi : 8,
+ tod_toa_reflector : 16,
packet_antenna : 8,
packet_pct1 : LeCsToneData,
packet_pct2 : LeCsToneData,
- tod_toa_reflector : 16,
antenna_permutation_index : 8,
tone_data : LeCsToneDataWithQuality[],
}
diff --git a/system/pdl/hci/include/hci/address.h b/system/pdl/hci/include/hci/address.h
index bc9c8d9127..7694689bf2 100644
--- a/system/pdl/hci/include/hci/address.h
+++ b/system/pdl/hci/include/hci/address.h
@@ -25,7 +25,6 @@
#include <ostream>
#include <string>
-#include "common/interfaces/ILoggable.h"
#include "os/logging/log_adapter.h"
#include "packet/custom_field_fixed_size_interface.h"
#include "storage/serializable.h"
@@ -34,8 +33,7 @@ namespace bluetooth {
namespace hci {
class Address final : public packet::CustomFieldFixedSizeInterface<Address>,
- public storage::Serializable<Address>,
- public bluetooth::common::IRedactableLoggable {
+ public storage::Serializable<Address> {
public:
static constexpr size_t kLength = 6;
@@ -56,11 +54,10 @@ public:
// storage::Serializable methods
std::string ToString() const override;
std::string ToColonSepHexString() const;
- std::string ToStringForLogging() const override;
- std::string ToRedactedStringForLogging() const override;
-
- static std::optional<Address> FromString(const std::string& from);
+ std::string ToStringForLogging() const;
+ std::string ToRedactedStringForLogging() const;
std::string ToLegacyConfigString() const override;
+ static std::optional<Address> FromString(const std::string& from);
static std::optional<Address> FromLegacyConfigString(const std::string& str);
bool operator<(const Address& rhs) const { return address < rhs.address; }
@@ -89,13 +86,6 @@ private:
std::string _ToMaskedColonSepHexString(int bytes_to_mask) const;
};
-// TODO: to fine-tune this.
-// we need an interface between the logger and ILoggable
-inline std::ostream& operator<<(std::ostream& os, const Address& a) {
- os << a.ToString();
- return os;
-}
-
} // namespace hci
} // namespace bluetooth
diff --git a/system/profile/avrcp/connection_handler.cc b/system/profile/avrcp/connection_handler.cc
index 146c079c77..0851b3320b 100644
--- a/system/profile/avrcp/connection_handler.cc
+++ b/system/profile/avrcp/connection_handler.cc
@@ -249,7 +249,7 @@ void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event, uint16
DCHECK(!connection_cb_.is_null());
log::info("handle=0x{:x} result=0x{:x} addr={}", handle, result,
- peer_addr ? ADDRESS_TO_LOGGABLE_STR(*peer_addr) : "none");
+ peer_addr ? peer_addr->ToRedactedStringForLogging() : "none");
switch (event) {
case AVRC_OPEN_IND_EVT: {
@@ -339,7 +339,7 @@ void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event, uint16_
DCHECK(!connection_cb_.is_null());
log::info("handle=0x{:x} result=0x{:x} addr={}", handle, result,
- peer_addr ? ADDRESS_TO_LOGGABLE_STR(*peer_addr) : "none");
+ peer_addr ? peer_addr->ToRedactedStringForLogging() : "none");
switch (event) {
case AVRC_OPEN_IND_EVT: {
@@ -406,10 +406,8 @@ void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event, uint16_
// as this one which will be closed when the device is disconnected.
AvrcpConnect(false, RawAddress::kAny);
- if (com::android::bluetooth::flags::avrcp_connect_a2dp_with_delay()) {
- // Check peer audio role: src or sink and connect A2DP after 3 seconds
- SdpLookupAudioRole(handle);
- }
+ // Check peer audio role: src or sink and connect A2DP after 3 seconds
+ SdpLookupAudioRole(handle);
} break;
case AVRC_CLOSE_IND_EVT: {
@@ -645,7 +643,7 @@ bool ConnectionHandler::SdpLookupAudioRole(uint16_t handle) {
log::info(
"Performing SDP for AUDIO_SINK on connected device: address={}, "
"handle={}",
- ADDRESS_TO_LOGGABLE_STR(device->GetAddress()), handle);
+ device->GetAddress(), handle);
return device->find_sink_service(base::Bind(&ConnectionHandler::SdpLookupAudioRoleCb,
weak_ptr_factory_.GetWeakPtr(), handle));
@@ -660,8 +658,8 @@ void ConnectionHandler::SdpLookupAudioRoleCb(uint16_t handle, bool found,
}
auto device = device_map_[handle];
- log::debug("SDP callback for address={}, handle={}, AUDIO_SINK {}",
- ADDRESS_TO_LOGGABLE_STR(device->GetAddress()), handle, found ? "found" : "not found");
+ log::debug("SDP callback for address={}, handle={}, AUDIO_SINK {}", device->GetAddress(), handle,
+ found ? "found" : "not found");
if (found) {
device->connect_a2dp_sink_delayed(handle);
diff --git a/system/profile/avrcp/device.cc b/system/profile/avrcp/device.cc
index a5012e8389..ef4fcda929 100644
--- a/system/profile/avrcp/device.cc
+++ b/system/profile/avrcp/device.cc
@@ -154,6 +154,7 @@ void Device::VendorPacketHandler(uint8_t label, std::shared_ptr<VendorPacket> pk
// TODO (apanicke): Add a retry mechanism if the response has a
// different volume than the one we set. For now, we don't care
// about the response to this message.
+ active_labels_.erase(label);
break;
default:
log::warn("{}: Unhandled Response: pdu={}", address_, pkt->GetCommandPdu());
@@ -1541,15 +1542,11 @@ void Device::SetBrowsedPlayerResponse(uint8_t label, std::shared_ptr<SetBrowsedP
return;
}
- // SetBrowsedPlayer can be called to retrieve the current path
- // and to verify that the player is still present, so we need to
- // keep current_path_ as is if the player is already the one browsed.
- // Otherwise, the current_path in the callback will contain the root id.
- if (pkt->GetPlayerId() != curr_browsed_player_id_) {
- curr_browsed_player_id_ = pkt->GetPlayerId();
- current_path_ = std::stack<std::string>();
- current_path_.push(current_path);
- }
+ curr_browsed_player_id_ = pkt->GetPlayerId();
+
+ // Clear the path and push the new root or current path.
+ current_path_ = std::stack<std::string>();
+ current_path_.push(current_path);
auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR, 0x0000, num_items,
0, current_path);
diff --git a/system/profile/avrcp/tests/avrcp_connection_handler_test.cc b/system/profile/avrcp/tests/avrcp_connection_handler_test.cc
index 080bda09f3..54f78edcd4 100644
--- a/system/profile/avrcp/tests/avrcp_connection_handler_test.cc
+++ b/system/profile/avrcp/tests/avrcp_connection_handler_test.cc
@@ -208,10 +208,8 @@ TEST_F(AvrcpConnectionHandlerTest, remoteDeviceConnectionTest) {
// device connects.
EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ROLE_ACCEPTOR)).Times(1);
- if (com::android::bluetooth::flags::avrcp_connect_a2dp_with_delay()) {
- // Set an expectation that SDP for audio will be performed
- EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
- }
+ // Set an expectation that SDP for audio will be performed
+ EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
// Call the callback with a message saying that a remote device has connected
conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
@@ -248,10 +246,8 @@ TEST_F(AvrcpConnectionHandlerTest, noAbsoluteVolumeTest) {
tAVRC_FIND_CBACK sdp_cb;
SetUpSdp(&sdp_cb, false, false);
- if (com::android::bluetooth::flags::avrcp_connect_a2dp_with_delay()) {
- // Set an expectation that SDP for audio will be performed
- EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
- }
+ // Set an expectation that SDP for audio will be performed
+ EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
EXPECT_CALL(mock_volume_, DeviceConnected(RawAddress::kAny)).Times(1);
@@ -292,10 +288,8 @@ TEST_F(AvrcpConnectionHandlerTest, absoluteVolumeTest) {
tAVRC_FIND_CBACK sdp_cb;
SetUpSdp(&sdp_cb, false, true);
- if (com::android::bluetooth::flags::avrcp_connect_a2dp_with_delay()) {
- // Set an expectation that SDP for audio will be performed
- EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
- }
+ // Set an expectation that SDP for audio will be performed
+ EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
// Call the callback with a message saying that a remote device has connected
conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
@@ -324,10 +318,8 @@ TEST_F(AvrcpConnectionHandlerTest, disconnectTest) {
&mock_volume_));
connection_handler_ = ConnectionHandler::Get();
- if (com::android::bluetooth::flags::avrcp_connect_a2dp_with_delay()) {
- // Set an expectation that SDP for audio will be performed
- EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
- }
+ // Set an expectation that SDP for audio will be performed
+ EXPECT_CALL(mock_a2dp_, find_audio_sink_service(_, _)).Times(1);
// Call the callback with a message saying that a remote device has connected
conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
diff --git a/system/rust/Android.bp b/system/rust/Android.bp
index 04be44dbec..592a686216 100644
--- a/system/rust/Android.bp
+++ b/system/rust/Android.bp
@@ -61,17 +61,6 @@ rust_defaults {
apex_available: ["com.android.btservices"],
}
-rust_library {
- name: "libbluetooth_core_rs_for_facade",
- crate_name: "bluetooth_core_rs_for_facade",
- defaults: ["libbluetooth_core_rs_defaults"],
- rustlibs: [
- "libbluetooth_aconfig_flags_rust",
- "libtokio",
- ],
- host_supported: true,
-}
-
rust_ffi_static {
name: "libbluetooth_core_rs",
crate_name: "bluetooth_core",
@@ -127,9 +116,6 @@ cc_library_static {
generated_headers: [
"cxx-bridge-header",
"libbluetooth_core_rs_bridge_codegen_header",
-
- "BluetoothGeneratedBundlerSchema_h_bfbs",
- "BluetoothGeneratedDumpsysDataSchema_h",
],
export_generated_headers: [
"cxx-bridge-header",
diff --git a/system/setup.py b/system/setup.py
deleted file mode 100644
index b593205e6e..0000000000
--- a/system/setup.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-from distutils import log
-import os
-from setuptools import find_packages
-from setuptools import setup
-from setuptools.command.install import install
-import stat
-import subprocess
-import sys
-
-reuse_libraries = False
-force_install = False
-
-install_requires = [
- 'grpcio',
- 'psutil',
- 'protobuf>=3.14.0, <4.0',
- 'mobly',
-]
-
-host_executables = [
- 'root-canal',
- 'bluetooth_stack_with_facade', # c++
- 'bluetooth_with_facades', # rust
- 'bt_topshim_facade', # topshim
-]
-
-
-def set_permissions_for_host_executables(outputs):
- for file in outputs:
- if os.path.basename(file) in host_executables:
- current_mode = os.stat(file).st_mode
- new_mode = current_mode | stat.S_IEXEC
- os.chmod(file, new_mode)
- log.log(log.INFO, "Changed file mode of %s from %s to %s" % (file, oct(current_mode), oct(new_mode)))
-
-
-class InstallLocalPackagesForInstallation(install):
-
- def run(self):
- global reuse_libraries, force_install
- install_args = [sys.executable, '-m', 'pip', 'install']
- subprocess.check_call(install_args + ['--upgrade', 'pip'])
-
- for package in install_requires:
- self.announce('Installing %s...' % package, log.INFO)
- cmd = install_args + ['-v', '--no-cache-dir', package]
- if force_install and not reuse_libraries:
- cmd.append("--force-reinstall")
- subprocess.check_call(cmd)
- self.announce('Dependencies installed.')
-
- install.run(self)
- set_permissions_for_host_executables(self.get_outputs())
-
-
-def main():
- global reuse_libraries, force_install
- if sys.argv[-1] == "--reuse-libraries":
- reuse_libraries = True
- sys.argv = sys.argv[:-1]
- if "--force" in sys.argv:
- force_install = True
- # Relative path from calling directory to this file
- our_dir = os.path.dirname(__file__)
- # Must cd into this dir for package resolution to work
- # This won't affect the calling shell
- os.chdir(our_dir)
- setup(
- name='bluetooth_cert_tests',
- version='1.0',
- author='Android Open Source Project',
- license='Apache2.0',
- description="""Bluetooth Cert Tests Package""",
- packages=[''] + find_packages(exclude=['llvm_binutils', 'llvm_binutils.*']),
- install_requires=install_requires,
- package_data={
- '': host_executables + ['*.so', 'lib64/*.so', 'target/*', 'llvm_binutils/bin/*', 'llvm_binutils/lib64/*'],
- },
- cmdclass={
- 'install': InstallLocalPackagesForInstallation,
- })
-
-
-if __name__ == '__main__':
- main()
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index 155dcd4208..2d690133f3 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -72,9 +72,6 @@ cc_library_static {
"packages/modules/Bluetooth/system/gd/hal",
"packages/modules/Bluetooth/system/udrv/include",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
"a2dp/a2dp_aac.cc",
"a2dp/a2dp_aac_decoder.cc",
@@ -322,7 +319,6 @@ cc_library_static {
"srvc/srvc_eng.cc",
],
generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
"cxx-bridge-header",
],
cflags: [
@@ -358,7 +354,6 @@ cc_defaults {
host_supported: true,
defaults: [
"bluetooth_cflags",
- "bluetooth_flatbuffer_bundler_defaults",
],
include_dirs: [
"packages/modules/Bluetooth/system",
@@ -442,6 +437,7 @@ cc_fuzz {
static_libs: [
"bluetooth_flags_c_lib",
"libbluetooth-types",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-platform-protos-lite",
],
@@ -460,14 +456,11 @@ cc_fuzz {
],
include_dirs: [
"external/flatbuffers/include",
- "external/rust/crates/quiche/deps/boringssl/src/include",
+ "external/rust/android-crates-io/crates/quiche/deps/boringssl/src/include",
"packages/modules/Bluetooth/system/stack/btm",
"packages/modules/Bluetooth/system/stack/test/common",
"packages/modules/Bluetooth/system/stack/test/rfcomm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothPacketSources",
":TestCommonMockFunctions",
@@ -516,12 +509,9 @@ cc_fuzz {
],
include_dirs: [
"external/flatbuffers/include",
- "external/rust/crates/quiche/deps/boringssl/src/include",
+ "external/rust/android-crates-io/crates/quiche/deps/boringssl/src/include",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothPacketSources",
":TestCommonMockFunctions",
@@ -571,12 +561,9 @@ cc_fuzz {
],
include_dirs: [
"external/flatbuffers/include",
- "external/rust/crates/quiche/deps/boringssl/src/include",
+ "external/rust/android-crates-io/crates/quiche/deps/boringssl/src/include",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothPacketSources",
":TestCommonMockFunctions",
@@ -620,12 +607,9 @@ cc_fuzz {
],
include_dirs: [
"external/flatbuffers/include",
- "external/rust/crates/quiche/deps/boringssl/src/include",
+ "external/rust/android-crates-io/crates/quiche/deps/boringssl/src/include",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothPacketSources",
":TestCommonMockFunctions",
@@ -661,12 +645,9 @@ cc_fuzz {
],
include_dirs: [
"external/flatbuffers/include",
- "external/rust/crates/quiche/deps/boringssl/src/include",
+ "external/rust/android-crates-io/crates/quiche/deps/boringssl/src/include",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothPacketSources",
":TestCommonMockFunctions",
@@ -711,12 +692,9 @@ cc_fuzz {
],
include_dirs: [
"external/flatbuffers/include",
- "external/rust/crates/quiche/deps/boringssl/src/include",
+ "external/rust/android-crates-io/crates/quiche/deps/boringssl/src/include",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothPacketSources",
":TestCommonMockFunctions",
@@ -740,6 +718,7 @@ cc_fuzz {
"libbluetooth_l2cap_pdl",
"libbluetooth_log",
"libbluetooth_smp_pdl",
+ "libbt-common",
"libbt-platform-protos-lite",
],
shared_libs: [
@@ -807,7 +786,6 @@ cc_test {
"bluetooth_flags_c_lib_for_test",
"libFraunhoferAAC",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-for-tests",
"libbluetooth-types",
"libbluetooth_core_rs",
@@ -909,9 +887,6 @@ cc_test {
"test/rfcomm/stack_rfcomm_test_utils.cc",
"test/rfcomm/stack_rfcomm_test_utils_test.cc",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
shared_libs: [
"libcrypto",
"libcutils",
@@ -957,7 +932,6 @@ cc_test {
cc_test {
name: "net_test_stack_smp",
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -998,9 +972,6 @@ cc_test {
"smp/smp_utils.cc",
"test/stack_smp_test.cc",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
shared_libs: [
"libaconfig_storage_read_api_cc",
"libcrypto",
@@ -1285,7 +1256,6 @@ cc_test {
"avdt/avdt_l2c.cc",
"avdt/avdt_scb.cc",
"avdt/avdt_scb_act.cc",
- "test/common/mock_btu_layer.cc",
"test/common/mock_stack_avdt_msg.cc",
"test/stack_avdtp_test.cc",
],
@@ -1517,6 +1487,7 @@ cc_test {
":TestMockMainShim",
":TestMockRustFfi",
":TestMockStackBtm",
+ ":TestMockStackConnMgr",
":TestMockStackL2cap",
":TestMockStackMetrics",
"gatt/gatt_db.cc",
@@ -1544,6 +1515,7 @@ cc_test {
"libbluetooth_core_rs_bridge",
"libbluetooth_crypto_toolbox",
"libbluetooth_gd",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-common",
"libbt-platform-protos-lite",
@@ -1572,7 +1544,6 @@ cc_test {
unit_test: true,
},
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -1581,9 +1552,6 @@ cc_test {
"include",
"test/common",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
include_dirs: [
"packages/modules/Bluetooth/system",
"packages/modules/Bluetooth/system/gd",
@@ -1634,7 +1602,6 @@ cc_test {
unit_test: true,
},
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -1651,9 +1618,6 @@ cc_test {
"packages/modules/Bluetooth/system/bta",
"packages/modules/Bluetooth/system/gd",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":TestCommonMainHandler",
":TestCommonMockFunctions",
@@ -1663,7 +1627,6 @@ cc_test {
":TestMockStackL2capInterface",
":TestStubOsi",
"eatt/eatt.cc",
- "test/common/mock_btif_storage.cc",
"test/common/mock_btm_api_layer.cc",
"test/common/mock_gatt_layer.cc",
"test/common/mock_l2cap_layer.cc",
@@ -1692,6 +1655,7 @@ cc_test {
"libprotobuf-cpp-lite",
"libstatslog_bt",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
target: {
android: {
@@ -1712,7 +1676,6 @@ cc_test {
unit_test: true,
},
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -1725,9 +1688,6 @@ cc_test {
"packages/modules/Bluetooth/system",
"packages/modules/Bluetooth/system/gd",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothHalSources_hci_host",
":BluetoothHalSources_ranging_host",
@@ -1930,6 +1890,7 @@ cc_test {
"libbase",
"libbluetooth-types",
"libbluetooth_crypto_toolbox",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-common",
"libbt-platform-protos-lite",
@@ -1981,9 +1942,6 @@ cc_test {
"packages/modules/Bluetooth/system/gd",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":TestCommonMockFunctions",
":TestMockBta",
@@ -2007,6 +1965,7 @@ cc_test {
"libbase",
"libbluetooth-types",
"libbluetooth_gd",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-common",
"libbt-platform-protos-lite",
@@ -2018,6 +1977,7 @@ cc_test {
"liblog",
"libosi",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
aidl: {
libs: ["bluetooth_constants"],
@@ -2057,9 +2017,6 @@ cc_test {
"packages/modules/Bluetooth/system/gd",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":OsiCompatSources",
":TestCommonMainHandler",
@@ -2076,6 +2033,7 @@ cc_test {
":TestMockStackAcl",
":TestMockStackBtm",
":TestMockStackL2cap",
+ ":TestMockStackMetrics",
":TestMockStackSdp",
":TestMockStackSmp",
"ais/ais_ble.cc",
@@ -2150,7 +2108,6 @@ cc_test {
test_suites: ["general-tests"],
host_supported: true,
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -2163,9 +2120,6 @@ cc_test {
"packages/modules/Bluetooth/system/gd",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":OsiCompatSources",
":TestCommonMainHandler",
@@ -2250,7 +2204,6 @@ cc_test {
test_suites: ["general-tests"],
host_supported: true,
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -2263,9 +2216,6 @@ cc_test {
"packages/modules/Bluetooth/system/gd",
"packages/modules/Bluetooth/system/stack/btm",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":OsiCompatSources",
":TestCommonMainHandler",
@@ -2298,6 +2248,7 @@ cc_test {
"libbluetooth-types",
"libbluetooth_core_rs_bridge",
"libbluetooth_gd",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-common",
"libbt-platform-protos-lite",
@@ -2348,7 +2299,6 @@ cc_test {
unit_test: true,
},
defaults: [
- "bluetooth_flatbuffer_bundler_defaults",
"fluoride_defaults",
"mts_defaults",
],
@@ -2361,9 +2311,6 @@ cc_test {
"packages/modules/Bluetooth/system",
"packages/modules/Bluetooth/system/gd",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
srcs: [
":BluetoothHalSources_hci_host",
":BluetoothHalSources_ranging_host",
@@ -2479,6 +2426,7 @@ cc_test {
"libbase",
"libbluetooth-types",
"libbluetooth_gd",
+ "libbluetooth_hci_pdl",
"libbluetooth_log",
"libbt-common",
"libbt-platform-protos-lite",
diff --git a/system/stack/a2dp/a2dp_sbc.cc b/system/stack/a2dp/a2dp_sbc.cc
index cac37e686e..f04fe13134 100644
--- a/system/stack/a2dp/a2dp_sbc.cc
+++ b/system/stack/a2dp/a2dp_sbc.cc
@@ -65,7 +65,11 @@ typedef struct {
/* SBC Source codec capabilities */
static const tA2DP_SBC_CIE a2dp_sbc_source_caps = {
- (A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+#ifdef TARGET_FLOSS
+ (A2DP_SBC_IE_SAMP_FREQ_48 | A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+#else
+ (A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+#endif
(A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_JOINT), /* ch_mode */
(A2DP_SBC_IE_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
A2DP_SBC_IE_BLOCKS_4), /* block_len */
@@ -92,7 +96,11 @@ static const tA2DP_SBC_CIE a2dp_sbc_sink_caps = {
/* Default SBC codec configuration */
const tA2DP_SBC_CIE a2dp_sbc_default_config = {
- A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
+#ifdef TARGET_FLOSS
+ (A2DP_SBC_IE_SAMP_FREQ_48), /* samp_freq */
+#else
+ (A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+#endif
A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */
A2DP_SBC_IE_BLOCKS_16, /* block_len */
A2DP_SBC_IE_SUBBAND_8, /* num_subbands */
diff --git a/system/stack/acl/btm_pm.cc b/system/stack/acl/btm_pm.cc
index 1914f30a38..15e0e51f28 100644
--- a/system/stack/acl/btm_pm.cc
+++ b/system/stack/acl/btm_pm.cc
@@ -31,7 +31,6 @@
#include "main/shim/entry.h"
#define LOG_TAG "bt_btm_pm"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -103,9 +102,9 @@ static void send_sniff_subrating(uint16_t handle, const RawAddress& addr, uint16
btsnd_hcic_sniff_sub_rate(handle, max_lat, min_rmt_to, min_loc_to);
BTM_LogHistory(kBtmLogTag, addr, "Sniff subrating",
- base::StringPrintf("max_latency:%.2f peer_timeout:%.2f local_timeout:%.2f",
- ticks_to_seconds(max_lat), ticks_to_seconds(min_rmt_to),
- ticks_to_seconds(min_loc_to)));
+ std::format("max_latency:{:.2f} peer_timeout:{:.2f} local_timeout:{:.2f}",
+ ticks_to_seconds(max_lat), ticks_to_seconds(min_rmt_to),
+ ticks_to_seconds(min_loc_to)));
}
static tBTM_STATUS btm_pm_snd_md_req(uint16_t handle, uint8_t pm_id, int link_ind,
@@ -555,9 +554,8 @@ static tBTM_STATUS btm_pm_snd_md_req(uint16_t handle, uint8_t pm_id, int link_in
log::info("Switching from {}[0x{:02x}] to {}[0x{:02x}]", power_mode_state_text(p_cb->state),
p_cb->state, power_mode_state_text(md_res.mode), md_res.mode);
BTM_LogHistory(kBtmLogTag, p_cb->bda_, "Power mode change",
- base::StringPrintf("%s[0x%02x] ==> %s[0x%02x]",
- power_mode_state_text(p_cb->state).c_str(), p_cb->state,
- power_mode_state_text(md_res.mode).c_str(), md_res.mode));
+ std::format("{}[0x{:02x}] ==> {}[0x{:02x}]", power_mode_state_text(p_cb->state),
+ p_cb->state, power_mode_state_text(md_res.mode), md_res.mode));
switch (md_res.mode) {
case BTM_PM_MD_ACTIVE:
diff --git a/system/stack/ais/ais_ble.cc b/system/stack/ais/ais_ble.cc
index 879797ed34..a4e4a65549 100644
--- a/system/stack/ais/ais_ble.cc
+++ b/system/stack/ais/ais_ble.cc
@@ -28,9 +28,6 @@
#include "stack/include/gatt_api.h"
#include "types/bluetooth/uuid.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using bluetooth::Uuid;
using bluetooth::log::error;
using bluetooth::log::warn;
@@ -104,7 +101,7 @@ void ais_request_cback(tCONN_ID conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type
* Returns void.
*
******************************************************************************/
-void ais_attr_db_init(void) {
+static void ais_attr_db_init(void) {
if (!com::android::bluetooth::flags::android_os_identifier()) {
return;
}
diff --git a/system/stack/avct/avct_api.cc b/system/stack/avct/avct_api.cc
index 33d58126c0..4369d68d13 100644
--- a/system/stack/avct/avct_api.cc
+++ b/system/stack/avct/avct_api.cc
@@ -70,9 +70,6 @@ void AVCT_Register() {
memset(&avct_cb, 0, sizeof(tAVCT_CB));
uint16_t sec = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
- if (!com::android::bluetooth::flags::use_encrypt_req_for_av()) {
- sec = BTA_SEC_AUTHENTICATE;
- }
/* register PSM with L2CAP */
if (!stack::l2cap::get_interface().L2CA_RegisterWithSecurity(
diff --git a/system/stack/avct/avct_bcb_act.cc b/system/stack/avct/avct_bcb_act.cc
index 68d10249e4..be2c90e43d 100644
--- a/system/stack/avct/avct_bcb_act.cc
+++ b/system/stack/avct/avct_bcb_act.cc
@@ -130,13 +130,8 @@ void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* /* p_data */) {
/* call l2cap connect req */
p_bcb->ch_state = AVCT_CH_CONN;
- if (com::android::bluetooth::flags::use_encrypt_req_for_av()) {
- p_bcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
- BT_PSM_AVCTP_BROWSE, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- } else {
- p_bcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
- BT_PSM_AVCTP_BROWSE, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE);
- }
+ p_bcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
+ BT_PSM_AVCTP_BROWSE, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
if (p_bcb->ch_lcid == 0) {
/* if connect req failed, send ourselves close event */
tAVCT_LCB_EVT avct_lcb_evt;
diff --git a/system/stack/avct/avct_lcb_act.cc b/system/stack/avct/avct_lcb_act.cc
index 9985a6fcbb..7770cd9e4a 100644
--- a/system/stack/avct/avct_lcb_act.cc
+++ b/system/stack/avct/avct_lcb_act.cc
@@ -192,13 +192,8 @@ void avct_lcb_chnl_open(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* /* p_data */) {
uint16_t result = AVCT_RESULT_FAIL;
p_lcb->ch_state = AVCT_CH_CONN;
- if (com::android::bluetooth::flags::use_encrypt_req_for_av()) {
- p_lcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
- BT_PSM_AVCTP, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- } else {
- p_lcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
- BT_PSM_AVCTP, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE);
- }
+ p_lcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
+ BT_PSM_AVCTP, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
if (p_lcb->ch_lcid == 0) {
/* if connect req failed, send ourselves close event */
tAVCT_LCB_EVT avct_lcb_evt;
diff --git a/system/stack/avdt/avdt_ad.cc b/system/stack/avdt/avdt_ad.cc
index fda9493690..938d4a4464 100644
--- a/system/stack/avdt/avdt_ad.cc
+++ b/system/stack/avdt/avdt_ad.cc
@@ -530,13 +530,8 @@ void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb, tAVDT_ROLE
p_tbl->state = AVDT_AD_ST_CONN;
/* call l2cap connect req */
- if (com::android::bluetooth::flags::use_encrypt_req_for_av()) {
- lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
- AVDT_PSM, p_ccb->peer_addr, BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
- } else {
- lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(AVDT_PSM, p_ccb->peer_addr,
- BTM_SEC_OUT_AUTHENTICATE);
- }
+ lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(
+ AVDT_PSM, p_ccb->peer_addr, BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
if (lcid == 0) {
/* if connect req failed, call avdt_ad_tc_close_ind() */
diff --git a/system/stack/avdt/avdt_api.cc b/system/stack/avdt/avdt_api.cc
index 207c090cd4..3a979e9c3a 100644
--- a/system/stack/avdt/avdt_api.cc
+++ b/system/stack/avdt/avdt_api.cc
@@ -104,9 +104,6 @@ void avdt_scb_transport_channel_timer_timeout(void* data) {
******************************************************************************/
void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) {
uint16_t sec = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
- if (!com::android::bluetooth::flags::use_encrypt_req_for_av()) {
- sec = BTA_SEC_AUTHENTICATE;
- }
/* register PSM with L2CAP */
if (!stack::l2cap::get_interface().L2CA_RegisterWithSecurity(
AVDT_PSM, avdt_l2c_appl, true /* enable_snoop */, nullptr, kAvdtpMtu, 0, sec)) {
@@ -981,7 +978,7 @@ void stack_debug_avdtp_api_dump(int fd) {
continue;
}
dprintf(fd, "\n Channel control block: %zu peer: %s\n", i,
- ADDRESS_TO_LOGGABLE_CSTR(ccb.peer_addr));
+ ccb.peer_addr.ToRedactedStringForLogging().c_str());
dprintf(fd, " Allocated: %s\n", ccb.allocated ? "true" : "false");
dprintf(fd, " State: %d\n", ccb.state);
dprintf(fd, " Link-layer opened: %s\n", ccb.ll_opened ? "true" : "false");
@@ -1010,7 +1007,8 @@ void stack_debug_avdtp_api_dump(int fd) {
dprintf(fd, " Transport channel connect timer: %s\n",
alarm_is_scheduled(scb.transport_channel_timer) ? "Scheduled" : "Not scheduled");
dprintf(fd, " Channel control block peer: %s\n",
- (scb.p_ccb != nullptr) ? ADDRESS_TO_LOGGABLE_CSTR(scb.p_ccb->peer_addr) : "null");
+ (scb.p_ccb != nullptr) ? scb.p_ccb->peer_addr.ToRedactedStringForLogging().c_str()
+ : "null");
dprintf(fd, " Allocated: %s\n", scb.allocated ? "true" : "false");
dprintf(fd, " In use: %s\n", scb.in_use ? "true" : "false");
dprintf(fd, " Role: 0x%x\n", scb.role);
diff --git a/system/stack/avdt/avdt_scb_act.cc b/system/stack/avdt/avdt_scb_act.cc
index 003f927c9c..e09cde8eeb 100644
--- a/system/stack/avdt/avdt_scb_act.cc
+++ b/system/stack/avdt/avdt_scb_act.cc
@@ -570,10 +570,9 @@ void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
// the codec type differs from the type of the SEP, or INVALID_CODEC_TYPE
// if the codec type does not match the values defined by Assigned Numbers.
if (local_codec_type != remote_codec_type) {
- p_data->msg.hdr.err_code =
- !com::android::bluetooth::flags::avdtp_error_codes() ? AVDTP_UNSUPPORTED_CONFIGURATION
- : !A2DP_IsCodecTypeValid(remote_codec_type) ? A2DP_INVALID_CODEC_TYPE
- : A2DP_NOT_SUPPORTED_CODEC_TYPE;
+ p_data->msg.hdr.err_code = !A2DP_IsCodecTypeValid(remote_codec_type)
+ ? A2DP_INVALID_CODEC_TYPE
+ : A2DP_NOT_SUPPORTED_CODEC_TYPE;
p_data->msg.hdr.err_param = 0;
avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), p_data->msg.hdr.sig_id,
&p_data->msg);
diff --git a/system/stack/bnep/bnep_utils.cc b/system/stack/bnep/bnep_utils.cc
index 0740451fda..64ea5f2501 100644
--- a/system/stack/bnep/bnep_utils.cc
+++ b/system/stack/bnep/bnep_utils.cc
@@ -45,9 +45,6 @@
#include "types/bt_transport.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
using bluetooth::Uuid;
@@ -56,8 +53,9 @@ using bluetooth::Uuid;
/******************************************************************************/
static uint8_t* bnepu_init_hdr(BT_HDR* p_buf, uint16_t hdr_len, uint8_t pkt_type);
-void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters, uint16_t len);
-void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code);
+static void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters,
+ uint16_t len);
+static void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code);
/*******************************************************************************
*
@@ -343,7 +341,7 @@ void bnepu_send_peer_our_multi_filters(tBNEP_CONN* p_bcb) {
* Returns void
*
******************************************************************************/
-void bnepu_send_peer_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code) {
+static void bnepu_send_peer_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code) {
BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
uint8_t* p;
@@ -1030,7 +1028,8 @@ void bnepu_process_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data) {
* Returns void
*
******************************************************************************/
-void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters, uint16_t len) {
+static void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters,
+ uint16_t len) {
uint16_t resp_code = BNEP_FILTER_CRL_OK;
uint16_t num_filters, xx;
uint8_t *p_temp_filters, null_bda[BD_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
@@ -1106,7 +1105,7 @@ void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filte
* Returns void
*
******************************************************************************/
-void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code) {
+static void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code) {
BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
uint8_t* p;
diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc
index 6f6e42b216..4b9cc79e32 100644
--- a/system/stack/btm/btm_ble_gap.cc
+++ b/system/stack/btm/btm_ble_gap.cc
@@ -30,6 +30,7 @@
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
+#include <bitset>
#include <cstdint>
#include <list>
#include <memory>
@@ -66,6 +67,7 @@
#include "stack/include/gattdefs.h"
#include "stack/include/hci_error_code.h"
#include "stack/include/inq_hci_link_interface.h"
+#include "stack/rnr/remote_name_request.h"
#include "types/ble_address_with_type.h"
#include "types/raw_address.h"
@@ -76,7 +78,6 @@ using namespace bluetooth;
extern tBTM_CB btm_cb;
-void btm_inq_remote_name_timer_timeout(void* data);
void btm_ble_adv_filter_init(void);
#define BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS (30 * 1000)
@@ -594,10 +595,10 @@ tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration, tBTM_INQ_RESULTS_CB* p_
} else if (btm_cb.ble_ctr_cb.is_ble_observe_active()) {
const uint64_t duration_timestamp =
timestamper_in_milliseconds.GetTimestamp() - btm_cb.neighbor.le_observe.start_time_ms;
- BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le observe stopped",
- base::StringPrintf("duration_s:%6.3f results:%-3lu",
- (double)duration_timestamp / 1000.0,
- (unsigned long)btm_cb.neighbor.le_observe.results));
+ BTM_LogHistory(
+ kBtmLogTag, RawAddress::kEmpty, "Le observe stopped",
+ std::format("duration_s:{:6.3f} results:{:<3}", (double)duration_timestamp / 1000.0,
+ btm_cb.neighbor.le_observe.results));
status = tBTM_STATUS::BTM_CMD_STARTED;
btm_ble_stop_observe();
} else {
@@ -1464,15 +1465,25 @@ void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int, uint16_t
uint8_t scan_phy, tBLE_ADDR_TYPE addr_type_own,
uint8_t scan_filter_policy) {
if (bluetooth::shim::GetController()->SupportsBleExtendedAdvertising()) {
- scanning_phy_cfg phy_cfg;
- phy_cfg.scan_type = scan_type;
- phy_cfg.scan_int = scan_int;
- phy_cfg.scan_win = scan_win;
-
if (com::android::bluetooth::flags::phy_to_native()) {
+ int phy_cnt = std::bitset<std::numeric_limits<uint8_t>::digits>(scan_phy).count();
+
+ scanning_phy_cfg phy_cfgs[phy_cnt];
+
+ for (int i = 0; i < phy_cnt; i++) {
+ phy_cfgs[i].scan_type = scan_type;
+ phy_cfgs[i].scan_int = scan_int;
+ phy_cfgs[i].scan_win = scan_win;
+ }
+
btsnd_hcic_ble_set_extended_scan_params(addr_type_own, scan_filter_policy, scan_phy,
- &phy_cfg);
+ phy_cfgs);
} else {
+ scanning_phy_cfg phy_cfg;
+ phy_cfg.scan_type = scan_type;
+ phy_cfg.scan_int = scan_int;
+ phy_cfg.scan_win = scan_win;
+
btsnd_hcic_ble_set_extended_scan_params(addr_type_own, scan_filter_policy, 1, &phy_cfg);
}
} else {
@@ -2425,8 +2436,8 @@ static void btm_ble_stop_scan(void) {
timestamper_in_milliseconds.GetTimestamp() - btm_cb.neighbor.le_legacy_scan.start_time_ms;
BTM_LogHistory(
kBtmLogTag, RawAddress::kEmpty, "Le legacy scan stopped",
- base::StringPrintf("duration_s:%6.3f results:%-3lu", (double)duration_timestamp / 1000.0,
- (unsigned long)btm_cb.neighbor.le_legacy_scan.results));
+ std::format("duration_s:{:6.3f} results:{:<3}", (double)duration_timestamp / 1000.0,
+ btm_cb.neighbor.le_legacy_scan.results));
btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
btm_update_scanner_filter_policy(SP_ADV_ALL);
@@ -2447,8 +2458,8 @@ void btm_ble_stop_inquiry(void) {
timestamper_in_milliseconds.GetTimestamp() - btm_cb.neighbor.le_inquiry.start_time_ms;
BTM_LogHistory(
kBtmLogTag, RawAddress::kEmpty, "Le inquiry stopped",
- base::StringPrintf("duration_s:%6.3f results:%-3lu", (double)duration_timestamp / 1000.0,
- (unsigned long)btm_cb.neighbor.le_inquiry.results));
+ std::format("duration_s:{:6.3f} results:{:<3}", (double)duration_timestamp / 1000.0,
+ btm_cb.neighbor.le_inquiry.results));
btm_cb.ble_ctr_cb.reset_ble_inquiry();
/* Cleanup anything remaining on index 0 */
diff --git a/system/stack/btm/btm_ble_sec.cc b/system/stack/btm/btm_ble_sec.cc
index 7ae82b335b..93d019cd08 100644
--- a/system/stack/btm/btm_ble_sec.cc
+++ b/system/stack/btm/btm_ble_sec.cc
@@ -20,7 +20,6 @@
#include "stack/btm/btm_ble_sec.h"
#include <android_bluetooth_sysprop.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -265,7 +264,7 @@ void BTM_SecurityGrant(const RawAddress& bd_addr, tBTM_STATUS res) {
(res == tBTM_STATUS::BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
log::verbose("bd_addr:{}, res:{}", bd_addr, smp_status_text(res_smp));
BTM_LogHistory(kBtmLogTag, bd_addr, "Granted",
- base::StringPrintf("passkey_status:%s", smp_status_text(res_smp).c_str()));
+ std::format("passkey_status:{}", smp_status_text(res_smp)));
SMP_SecurityGrant(bd_addr, res_smp);
}
@@ -295,9 +294,8 @@ void BTM_BlePasskeyReply(const RawAddress& bd_addr, tBTM_STATUS res, uint32_t pa
const tSMP_STATUS res_smp =
(res == tBTM_STATUS::BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
BTM_LogHistory(kBtmLogTag, bd_addr, "Passkey reply",
- base::StringPrintf("transport:%s authenticate_status:%s",
- bt_transport_text(BT_TRANSPORT_LE).c_str(),
- smp_status_text(res_smp).c_str()));
+ std::format("transport:{} authenticate_status:{}",
+ bt_transport_text(BT_TRANSPORT_LE), smp_status_text(res_smp)));
p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED;
SMP_PasskeyReply(bd_addr, res_smp, passkey);
@@ -326,9 +324,8 @@ void BTM_BleConfirmReply(const RawAddress& bd_addr, tBTM_STATUS res) {
(res == tBTM_STATUS::BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
BTM_LogHistory(kBtmLogTag, bd_addr, "Confirm reply",
- base::StringPrintf("transport:%s numeric_comparison_authenticate_status:%s",
- bt_transport_text(BT_TRANSPORT_LE).c_str(),
- smp_status_text(res_smp).c_str()));
+ std::format("transport:{} numeric_comparison_authenticate_status:{}",
+ bt_transport_text(BT_TRANSPORT_LE), smp_status_text(res_smp)));
p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED;
SMP_ConfirmReply(bd_addr, res_smp);
@@ -358,9 +355,8 @@ void BTM_BleOobDataReply(const RawAddress& bd_addr, tBTM_STATUS res, uint8_t len
const tSMP_STATUS res_smp = (res == tBTM_STATUS::BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
BTM_LogHistory(kBtmLogTag, bd_addr, "Oob data reply",
- base::StringPrintf("transport:%s authenticate_status:%s",
- bt_transport_text(BT_TRANSPORT_LE).c_str(),
- smp_status_text(res_smp).c_str()));
+ std::format("transport:{} authenticate_status:{}",
+ bt_transport_text(BT_TRANSPORT_LE), smp_status_text(res_smp)));
p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED;
SMP_OobDataReply(bd_addr, res_smp, len, p_data);
@@ -387,7 +383,7 @@ void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr, uint8_t* p_c
}
BTM_LogHistory(kBtmLogTag, bd_addr, "Oob data reply",
- base::StringPrintf("transport:%s", bt_transport_text(BT_TRANSPORT_LE).c_str()));
+ std::format("transport:{}", bt_transport_text(BT_TRANSPORT_LE)));
p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED;
@@ -1147,6 +1143,10 @@ tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr, tBTM_BLE_SEC_ACT s
switch (sec_act) {
case BTM_BLE_SEC_ENCRYPT:
+ if (p_rec->sec_rec.is_le_device_encrypted()) {
+ return tBTM_STATUS::BTM_SUCCESS;
+ }
+
if (link_role == HCI_ROLE_CENTRAL) {
/* start link layer encryption using the security info stored */
cmd = btm_ble_start_encrypt(bd_addr, false, NULL);
@@ -1407,6 +1407,42 @@ void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk, const Octet1
btsnd_hcic_ble_ltk_req_reply(btm_sec_cb.enc_handle, p_rec->sec_rec.ble_keys.lltk);
}
+static void btm_ble_get_auth_req(const tBTM_SEC_DEV_REC* p_dev_rec, tBTM_LE_AUTH_REQ* p_auth_req) {
+ // If the device is bonded and we are trying to encrypt the link with it as a
+ // peripheral, then we need to ensure that the authentication requirements
+ // match what was agreed upon during bonding.
+ if (com::android::bluetooth::flags::peripheral_auth_req() &&
+ btm_sec_cb.pairing_bda != p_dev_rec->bd_addr &&
+ btm_sec_cb.pairing_bda != p_dev_rec->ble.pseudo_addr) { // Not pairing
+ if (!p_dev_rec->role_central && p_dev_rec->sec_rec.is_le_link_key_known() &&
+ p_dev_rec->sec_rec.ble_keys.key_type != BTM_LE_KEY_NONE &&
+ p_dev_rec->sec_rec.le_link == tSECURITY_STATE::AUTHENTICATING) {
+ // Trying to encrypt the link with already bonded device in peripheral role
+ if ((p_dev_rec->sec_rec.security_required & BTM_SEC_IN_MITM) ||
+ p_dev_rec->sec_rec.ble_keys.sec_level == SMP_SEC_AUTHENTICATED) {
+ // Authentication required or existing bond record was authenticated
+ *p_auth_req |= BTM_LE_AUTH_REQ_MITM;
+ } else {
+ // No authentication required and no bond record
+ *p_auth_req &= ~BTM_LE_AUTH_REQ_MITM;
+ }
+
+ // Request Secure Connections only if the remote device claim support earlier
+ if (p_dev_rec->SupportsSecureConnections()) {
+ *p_auth_req |= BTM_LE_AUTH_REQ_SC_ONLY;
+ } else {
+ *p_auth_req &= ~BTM_LE_AUTH_REQ_SC_ONLY;
+ }
+ return;
+ }
+ }
+
+ /* Authentication requested? */
+ if (p_dev_rec->sec_rec.security_required & BTM_SEC_IN_MITM) {
+ *p_auth_req |= BTM_LE_AUTH_REQ_MITM;
+ }
+}
+
/*******************************************************************************
*
* Function btm_ble_io_capabilities_req
@@ -1439,10 +1475,7 @@ static tBTM_STATUS btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec,
log::verbose("2:i_keys=0x{:x} r_keys=0x{:x} (bit 0-LTK 1-IRK 2-CSRK)", p_data->init_keys,
p_data->resp_keys);
- /* if authentication requires MITM protection, put on the mask */
- if (p_dev_rec->sec_rec.security_required & BTM_SEC_IN_MITM) {
- p_data->auth_req |= BTM_LE_AUTH_REQ_MITM;
- }
+ btm_ble_get_auth_req(p_dev_rec, &p_data->auth_req);
if (!(p_data->auth_req & SMP_AUTH_BOND)) {
log::verbose("Non bonding: No keys should be exchanged");
@@ -1555,13 +1588,22 @@ void btm_ble_connected(const RawAddress& bda, uint16_t handle, uint8_t /* enc_mo
*
******************************************************************************/
void btm_ble_connection_established(const RawAddress& bda) {
- if (!com::android::bluetooth::flags::name_discovery_for_le_pairing()) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+ if (p_dev_rec == nullptr) {
+ log::warn("No security record for {}", bda);
return;
}
+ // Encrypt the link if device is bonded
+ if (com::android::bluetooth::flags::le_enc_on_reconnection() &&
+ p_dev_rec->sec_rec.is_le_link_key_known()) {
+ btm_ble_set_encryption(bda, BTM_BLE_SEC_ENCRYPT,
+ p_dev_rec->role_central ? HCI_ROLE_CENTRAL : HCI_ROLE_PERIPHERAL);
+ }
+
// Read device name if it is not known already, we may need it for pairing
- tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
- if (p_dev_rec != nullptr && !p_dev_rec->sec_rec.is_name_known()) {
+ if (com::android::bluetooth::flags::name_discovery_for_le_pairing() &&
+ !p_dev_rec->sec_rec.is_name_known()) {
btm_ble_read_remote_name(bda, nullptr);
}
@@ -1575,6 +1617,34 @@ void btm_ble_connection_established(const RawAddress& bda) {
}
}
+static bool btm_ble_complete_evt_ignore(const tBTM_SEC_DEV_REC* p_dev_rec,
+ const tBTM_LE_EVT_DATA* p_data) {
+ if (!com::android::bluetooth::flags::bonded_device_smp_failure_handling()) {
+ return false;
+ }
+ // Encryption request in peripheral role results in SMP Security request. SMP may generate a
+ // SMP_COMPLT_EVT failure event cases like below:
+ // 1) Some central devices don't handle cross-over between encryption and SMP security request
+ // 2) Link may get disconnected after the SMP security request was sent.
+ if (p_data->complt.reason != SMP_SUCCESS && !p_dev_rec->role_central &&
+ btm_sec_cb.pairing_bda != p_dev_rec->bd_addr &&
+ btm_sec_cb.pairing_bda != p_dev_rec->ble.pseudo_addr &&
+ p_dev_rec->sec_rec.is_le_link_key_known() &&
+ p_dev_rec->sec_rec.ble_keys.key_type != BTM_LE_KEY_NONE) {
+ if (p_dev_rec->sec_rec.is_le_device_encrypted()) {
+ log::warn("Bonded device {} is already encrypted, ignoring SMP failure", p_dev_rec->bd_addr);
+ return true;
+ } else if (p_data->complt.reason == SMP_CONN_TOUT) {
+ log::warn("Bonded device {} disconnected while waiting for encryption, ignoring SMP failure",
+ p_dev_rec->bd_addr);
+ l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void btm_ble_user_confirmation_req(const RawAddress& bd_addr, tBTM_SEC_DEV_REC* p_dev_rec,
tBTM_LE_EVT event, tBTM_LE_EVT_DATA* p_data) {
p_dev_rec->sec_rec.sec_flags |= BTM_SEC_LE_AUTHENTICATED;
@@ -1604,6 +1674,11 @@ static void btm_ble_consent_req(const RawAddress& bd_addr, tBTM_LE_EVT_DATA* p_d
static void btm_ble_complete_evt(const RawAddress& bd_addr, tBTM_SEC_DEV_REC* p_dev_rec,
tBTM_LE_EVT_DATA* p_data) {
+
+ if (btm_ble_complete_evt_ignore(p_dev_rec, p_data)) {
+ return;
+ }
+
BTM_BLE_SEC_CALLBACK(BTM_LE_COMPLT_EVT, bd_addr, p_data);
log::verbose("before update sec_level=0x{:x} sec_flags=0x{:x}", p_data->complt.sec_level,
@@ -1865,7 +1940,7 @@ void BTM_BleSirkConfirmDeviceReply(const RawAddress& bd_addr, tBTM_STATUS res) {
}
BTM_LogHistory(kBtmLogTag, bd_addr, "SIRK confirmation",
- base::StringPrintf("status:%s", smp_status_text(res_smp).c_str()));
+ std::format("status:{}", smp_status_text(res_smp)));
SMP_SirkConfirmDeviceReply(bd_addr, res_smp);
}
diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc
index 6712527fe7..4840a6d36e 100644
--- a/system/stack/btm/btm_dev.cc
+++ b/system/stack/btm/btm_dev.cc
@@ -192,10 +192,9 @@ bool BTM_SecDeleteDevice(const RawAddress& bd_addr) {
/* Tell controller to get rid of the link key, if it has one stored */
BTM_DeleteStoredLinkKey(&bda, NULL);
log::info("{} complete", bd_addr);
- BTM_LogHistory(
- kBtmLogTag, bd_addr, "Device removed",
- base::StringPrintf("device_type:%s bond_type:%s", DeviceTypeText(device_type).c_str(),
- bond_type_text(bond_type).c_str()));
+ BTM_LogHistory(kBtmLogTag, bd_addr, "Device removed",
+ std::format("device_type:{} bond_type:{}", DeviceTypeText(device_type),
+ bond_type_text(bond_type)));
return true;
}
diff --git a/system/stack/btm/btm_inq.cc b/system/stack/btm/btm_inq.cc
index 32debc62e1..b1ed1c6d03 100644
--- a/system/stack/btm/btm_inq.cc
+++ b/system/stack/btm/btm_inq.cc
@@ -98,9 +98,9 @@ void btm_log_history_scan_mode(uint8_t scan_mode) {
}
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Classic updated",
- base::StringPrintf("inquiry_scan_enable:%c page_scan_enable:%c",
- (scan_mode & HCI_INQUIRY_SCAN_ENABLED) ? 'T' : 'F',
- (scan_mode & HCI_PAGE_SCAN_ENABLED) ? 'T' : 'F'));
+ std::format("inquiry_scan_enable:{:c} page_scan_enable:{:c}",
+ (scan_mode & HCI_INQUIRY_SCAN_ENABLED) ? 'T' : 'F',
+ (scan_mode & HCI_PAGE_SCAN_ENABLED) ? 'T' : 'F'));
scan_mode_cached_ = scan_mode;
}
@@ -563,12 +563,11 @@ void BTM_CancelInquiry(void) {
const auto duration_ms = timestamper_in_milliseconds.GetTimestamp() -
btm_cb.neighbor.classic_inquiry.start_time_ms;
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Classic inquiry canceled",
- base::StringPrintf(
- "duration_s:%6.3f results:%lu std:%u rssi:%u ext:%u", duration_ms / 1000.0,
- (unsigned long)btm_cb.neighbor.classic_inquiry.results,
- btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD],
- btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI],
- btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_EXTENDED]));
+ std::format("duration_s:{:6.3f} results:{} std:{} rssi:{} ext:{}",
+ duration_ms / 1000.0, btm_cb.neighbor.classic_inquiry.results,
+ btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD],
+ btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI],
+ btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_EXTENDED]));
btm_cb.neighbor.classic_inquiry = {};
/* Only cancel if not in periodic mode, otherwise the caller should call
@@ -710,9 +709,9 @@ tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb, tBTM_CMPL_CB* p_
}
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Classic inquiry started",
- base::StringPrintf("%s", (btm_cb.neighbor.classic_inquiry.start_time_ms == 0)
- ? ""
- : "ERROR Already in progress"));
+ std::format("{}", (btm_cb.neighbor.classic_inquiry.start_time_ms == 0)
+ ? ""
+ : "ERROR Already in progress"));
const uint8_t inq_length =
osi_property_get_int32(PROPERTY_INQ_LENGTH, BTIF_DM_DEFAULT_INQ_MAX_DURATION);
@@ -1690,16 +1689,16 @@ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) {
.start_time_ms = btm_cb.neighbor.classic_inquiry.start_time_ms,
});
const auto end_time_ms = timestamper_in_milliseconds.GetTimestamp();
- BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Classic inquiry complete",
- base::StringPrintf(
- "duration_s:%6.3f results:%lu inq_active:0x%02x std:%u rssi:%u "
- "ext:%u status:%s",
- (end_time_ms - btm_cb.neighbor.classic_inquiry.start_time_ms) / 1000.0,
- (unsigned long)btm_cb.neighbor.classic_inquiry.results, inq_active,
- btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD],
- btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI],
- btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_EXTENDED],
- hci_error_code_text(status).c_str()));
+ BTM_LogHistory(
+ kBtmLogTag, RawAddress::kEmpty, "Classic inquiry complete",
+ std::format("duration_s:{:6.3f} results:{} inq_active:0x{:02x} std:{} rssi:{} ext:{} "
+ "status:{}",
+ (end_time_ms - btm_cb.neighbor.classic_inquiry.start_time_ms) / 1000.0,
+ btm_cb.neighbor.classic_inquiry.results, inq_active,
+ btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_STANDARD],
+ btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_WITH_RSSI],
+ btm_cb.btm_inq_vars.inq_cmpl_info.resp_type[BTM_INQ_RESULT_EXTENDED],
+ hci_error_code_text(status)));
btm_cb.neighbor.classic_inquiry.start_time_ms = 0;
/* Clear the results callback if set */
diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h
index cdda94f0a2..e99e99f557 100644
--- a/system/stack/btm/btm_iso_impl.h
+++ b/system/stack/btm/btm_iso_impl.h
@@ -133,8 +133,8 @@ struct iso_impl {
IsCigKnown(cig_id) ? kIsoEventCigOnReconfigureCmpl : kIsoEventCigOnCreateCmpl;
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "CIG Create complete",
- base::StringPrintf("cig_id:0x%02x, status: %s", evt.cig_id,
- hci_status_code_text((tHCI_STATUS)(evt.status)).c_str()));
+ std::format("cig_id:0x{:02x}, status: {}", evt.cig_id,
+ hci_status_code_text((tHCI_STATUS)(evt.status))));
if (evt.status == HCI_SUCCESS) {
log::assert_that(len >= (3) + (cis_cnt * sizeof(uint16_t)), "Invalid CIS count: {}", cis_cnt);
@@ -188,8 +188,7 @@ struct iso_impl {
cig_params.sdu_itv_mtos));
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "CIG Create",
- base::StringPrintf("cig_id:0x%02x, size: %d", cig_id,
- static_cast<int>(cig_params.cis_cfgs.size())));
+ std::format("cig_id:0x{:02x}, size: {}", cig_id, cig_params.cis_cfgs.size()));
}
void reconfigure_cig(uint8_t cig_id, struct iso_manager::cig_create_params cig_params) {
@@ -213,8 +212,8 @@ struct iso_impl {
STREAM_TO_UINT8(evt.cig_id, stream);
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "CIG Remove complete",
- base::StringPrintf("cig_id:0x%02x, status: %s", evt.cig_id,
- hci_status_code_text((tHCI_STATUS)(evt.status)).c_str()));
+ std::format("cig_id:0x{:02x}, status: {}", evt.cig_id,
+ hci_status_code_text((tHCI_STATUS)(evt.status))));
if (evt.status == HCI_SUCCESS) {
auto cis_it = conn_hdl_to_cis_map_.cbegin();
@@ -247,7 +246,7 @@ struct iso_impl {
btsnd_hcic_remove_cig(cig_id,
base::BindOnce(&iso_impl::on_remove_cig, weak_factory_.GetWeakPtr()));
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "CIG Remove",
- base::StringPrintf("cig_id:0x%02x (f:%d)", cig_id, force));
+ std::format("cig_id:0x{:02x} (f:{})", cig_id, force));
}
void on_status_establish_cis(struct iso_manager::cis_establish_params conn_params,
@@ -272,8 +271,8 @@ struct iso_impl {
cig_callbacks_->OnCisEvent(kIsoEventCisEstablishCmpl, &evt);
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[evt.cis_conn_hdl], "Establish CIS failed ",
- base::StringPrintf("handle:0x%04x, status: %s", evt.cis_conn_hdl,
- hci_status_code_text((tHCI_STATUS)(status)).c_str()));
+ std::format("handle:0x{:04x}, status: {}", evt.cis_conn_hdl,
+ hci_status_code_text((tHCI_STATUS)(status))));
cis_hdl_to_addr.erase(evt.cis_conn_hdl);
}
}
@@ -295,7 +294,7 @@ struct iso_impl {
if (p_rec) {
cis_hdl_to_addr[el.cis_conn_handle] = p_rec->ble.pseudo_addr;
BTM_LogHistory(kBtmLogTag, p_rec->ble.pseudo_addr, "Establish CIS",
- base::StringPrintf("handle:0x%04x", el.acl_conn_handle));
+ std::format("handle:0x{:04x}", el.acl_conn_handle));
}
}
btsnd_hcic_create_cis(conn_params.conn_pairs.size(), conn_params.conn_pairs.data(),
@@ -318,8 +317,8 @@ struct iso_impl {
bluetooth::legacy::hci::GetInterface().Disconnect(cis_handle, static_cast<tHCI_STATUS>(reason));
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[cis_handle], "Disconnect CIS ",
- base::StringPrintf("handle:0x%04x, reason:%s", cis_handle,
- hci_reason_code_text((tHCI_REASON)(reason)).c_str()));
+ std::format("handle:0x{:04x}, reason:{}", cis_handle,
+ hci_reason_code_text((tHCI_REASON)(reason))));
}
int get_number_of_active_iso() {
@@ -344,8 +343,8 @@ struct iso_impl {
}
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[conn_handle], "Setup data path complete",
- base::StringPrintf("handle:0x%04x, status:%s", conn_handle,
- hci_status_code_text((tHCI_STATUS)(status)).c_str()));
+ std::format("handle:0x{:04x}, status:{}", conn_handle,
+ hci_status_code_text((tHCI_STATUS)(status))));
if (status == HCI_SUCCESS) {
iso->state_flags |= kStateFlagHasDataPathSet;
@@ -374,9 +373,9 @@ struct iso_impl {
path_params.controller_delay, std::move(path_params.codec_conf),
base::BindOnce(&iso_impl::on_setup_iso_data_path, weak_factory_.GetWeakPtr()));
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[conn_handle], "Setup data path",
- base::StringPrintf("handle:0x%04x, dir:0x%02x, path_id:0x%02x, codec_id:0x%02x",
- conn_handle, path_params.data_path_dir,
- path_params.data_path_id, path_params.codec_id_format));
+ std::format("handle:0x{:04x}, dir:0x{:02x}, path_id:0x{:02x}, codec_id:0x{:02x}",
+ conn_handle, path_params.data_path_dir, path_params.data_path_id,
+ path_params.codec_id_format));
}
void on_remove_iso_data_path(uint8_t* stream, uint16_t len) {
@@ -399,8 +398,8 @@ struct iso_impl {
}
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[conn_handle], "Remove data path complete",
- base::StringPrintf("handle:0x%04x, status:%s", conn_handle,
- hci_status_code_text((tHCI_STATUS)(status)).c_str()));
+ std::format("handle:0x{:04x}, status:{}", conn_handle,
+ hci_status_code_text((tHCI_STATUS)(status))));
if (status == HCI_SUCCESS) {
iso->state_flags &= ~kStateFlagHasDataPathSet;
@@ -426,7 +425,7 @@ struct iso_impl {
base::BindOnce(&iso_impl::on_remove_iso_data_path, weak_factory_.GetWeakPtr()));
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[iso_handle], "Remove data path",
- base::StringPrintf("handle:0x%04x, dir:0x%02x", iso_handle, data_path_dir));
+ std::format("handle:0x{:04x}, dir:0x{:02x}", iso_handle, data_path_dir));
}
void on_iso_link_quality_read(uint8_t* stream, uint16_t len) {
@@ -565,8 +564,8 @@ struct iso_impl {
log::assert_that(cis != nullptr, "No such cis: {}", evt.cis_conn_hdl);
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[evt.cis_conn_hdl], "CIS established event",
- base::StringPrintf("cis_handle:0x%04x status:%s", evt.cis_conn_hdl,
- hci_error_code_text((tHCI_STATUS)(evt.status)).c_str()));
+ std::format("cis_handle:0x{:04x} status:{}", evt.cis_conn_hdl,
+ hci_error_code_text((tHCI_STATUS)(evt.status))));
STREAM_TO_UINT24(evt.cig_sync_delay, data);
STREAM_TO_UINT24(evt.cis_sync_delay, data);
@@ -607,8 +606,8 @@ struct iso_impl {
log::info("flags: {}", cis->state_flags);
BTM_LogHistory(kBtmLogTag, cis_hdl_to_addr[handle], "CIS disconnected",
- base::StringPrintf("cis_handle:0x%04x, reason:%s", handle,
- hci_error_code_text((tHCI_REASON)(reason)).c_str()));
+ std::format("cis_handle:0x{:04x}, reason:{}", handle,
+ hci_error_code_text((tHCI_REASON)(reason))));
cis_hdl_to_addr.erase(handle);
if (cis->state_flags & kStateFlagIsConnected || cis->state_flags & kStateFlagIsCancelled) {
diff --git a/system/stack/btm/btm_main.cc b/system/stack/btm/btm_main.cc
index d07769b157..581b4d6445 100644
--- a/system/stack/btm/btm_main.cc
+++ b/system/stack/btm/btm_main.cc
@@ -81,7 +81,7 @@ static void btm_log_history(const std::string& tag, const char* addr, const std:
void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, const std::string& msg,
const std::string& extra) {
- btm_log_history(tag, ADDRESS_TO_LOGGABLE_CSTR(bd_addr), msg, extra);
+ btm_log_history(tag, bd_addr.ToRedactedStringForLogging().c_str(), msg, extra);
}
void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, const std::string& msg) {
@@ -90,7 +90,7 @@ void BTM_LogHistory(const std::string& tag, const RawAddress& bd_addr, const std
void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr, const std::string& msg,
const std::string& extra) {
- btm_log_history(tag, ADDRESS_TO_LOGGABLE_CSTR(ble_bd_addr), msg, extra);
+ btm_log_history(tag, ble_bd_addr.ToRedactedStringForLogging().c_str(), msg, extra);
}
void BTM_LogHistory(const std::string& tag, const tBLE_BD_ADDR& ble_bd_addr,
diff --git a/system/stack/btm/btm_sco.cc b/system/stack/btm/btm_sco.cc
index 1aba506513..ecb0c4d734 100644
--- a/system/stack/btm/btm_sco.cc
+++ b/system/stack/btm/btm_sco.cc
@@ -27,7 +27,6 @@
#include "stack/btm/btm_sco.h"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -810,7 +809,7 @@ tBTM_STATUS BTM_CreateSco(const RawAddress* remote_bda, bool is_orig, uint16_t p
log::debug("SCO connection successfully requested");
if (p->state == SCO_ST_CONNECTING) {
BTM_LogHistory(kBtmLogTag, *remote_bda, "Connecting",
- base::StringPrintf("local initiated acl:0x%04x", acl_handle));
+ std::format("local initiated acl:0x{:04x}", acl_handle));
}
return tBTM_STATUS::BTM_CMD_STARTED;
}
@@ -1005,7 +1004,7 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, tBTM_ESCO_DAT
(p->state == SCO_ST_W4_CONN_RSP)) &&
(p->rem_bd_known) && (p->esco.data.bd_addr == bda)) {
BTM_LogHistory(kBtmLogTag, bda, "Connection created",
- base::StringPrintf("sco_idx:%hu handle:0x%04x ", xx, hci_handle));
+ std::format("sco_idx:{} handle:0x{:04x}", xx, hci_handle));
power_telemetry::GetInstance().LogLinkDetails(hci_handle, bda, true, false);
if (p->state == SCO_ST_LISTENING) {
@@ -1017,7 +1016,7 @@ void btm_sco_connected(const RawAddress& bda, uint16_t hci_handle, tBTM_ESCO_DAT
BTM_LogHistory(
kBtmLogTag, bda, "Connection success",
- base::StringPrintf("handle:0x%04x %s", hci_handle, (spt) ? "listener" : "initiator"));
+ std::format("handle:0x{:04x} {}", hci_handle, (spt) ? "listener" : "initiator"));
log::debug("Connected SCO link handle:0x{:04x} peer:{}", hci_handle, bda);
if (!btm_cb.sco_cb.esco_supported) {
@@ -1080,19 +1079,17 @@ void btm_sco_create_command_status_failed(tHCI_STATUS hci_status) {
(*p->p_disc_cb)(idx);
BTM_LogHistory(kBtmLogTag, p->esco.data.bd_addr, "Connection failed",
- base::StringPrintf(
- "locally_initiated reason:%s",
- hci_reason_code_text(static_cast<tHCI_REASON>(hci_status)).c_str()));
+ std::format("locally_initiated reason:{}",
+ hci_reason_code_text(static_cast<tHCI_REASON>(hci_status))));
return;
}
}
log::warn("No context found for the SCO connection failed");
- BTM_LogHistory(
- kBtmLogTag, RawAddress::kEmpty, "Connection failed",
- base::StringPrintf("locally_initiated reason:%s",
- hci_reason_code_text(static_cast<tHCI_REASON>(hci_status)).c_str()));
+ BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Connection failed",
+ std::format("locally_initiated reason:{}",
+ hci_reason_code_text(static_cast<tHCI_REASON>(hci_status))));
}
/*******************************************************************************
@@ -1133,9 +1130,8 @@ void btm_sco_connection_failed(tHCI_STATUS hci_status, const RawAddress& bda, ui
(*p->p_disc_cb)(xx);
}
BTM_LogHistory(kBtmLogTag, bda, "Connection failed",
- base::StringPrintf(
- "locally_initiated reason:%s",
- hci_reason_code_text(static_cast<tHCI_REASON>(hci_status)).c_str()));
+ std::format("locally_initiated reason:{}",
+ hci_reason_code_text(static_cast<tHCI_REASON>(hci_status))));
} else {
log::debug("SCO terminating connection failed handle:0x{:04x} reason:{}", hci_handle,
hci_error_code_text(hci_status));
@@ -1149,9 +1145,8 @@ void btm_sco_connection_failed(tHCI_STATUS hci_status, const RawAddress& bda, ui
}
}
BTM_LogHistory(kBtmLogTag, bda, "Connection failed",
- base::StringPrintf(
- "remote_initiated reason:%s",
- hci_reason_code_text(static_cast<tHCI_REASON>(hci_status)).c_str()));
+ std::format("remote_initiated reason:{}",
+ hci_reason_code_text(static_cast<tHCI_REASON>(hci_status))));
}
return;
}
@@ -1203,8 +1198,8 @@ tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) {
log::debug("Disconnecting link sco_handle:0x{:04x} peer:{}", p->Handle(), p->esco.data.bd_addr);
BTM_LogHistory(kBtmLogTag, p->esco.data.bd_addr, "Disconnecting",
- base::StringPrintf("local initiated handle:0x%04x previous_state:%s", p->Handle(),
- sco_state_text(old_state).c_str()));
+ std::format("local initiated handle:0x{:04x} previous_state:{}", p->Handle(),
+ sco_state_text(old_state)));
return tBTM_STATUS::BTM_CMD_STARTED;
}
@@ -1287,9 +1282,9 @@ void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) {
p_sco->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
(*p_sco->p_disc_cb)(btm_cb.sco_cb.get_index(p_sco));
log::debug("Disconnected SCO link handle:{} reason:{}", hci_handle, hci_reason_code_text(reason));
- BTM_LogHistory(kBtmLogTag, bd_addr, "Disconnected",
- base::StringPrintf("handle:0x%04x reason:%s", hci_handle,
- hci_reason_code_text(reason).c_str()));
+ BTM_LogHistory(
+ kBtmLogTag, bd_addr, "Disconnected",
+ std::format("handle:0x{:04x} reason:{}", hci_handle, hci_reason_code_text(reason)));
hfp_hal_interface::notify_sco_connection_change(
bd_addr, /*is_connected=*/false,
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 8c6d057f53..7df5f2bd4a 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -28,7 +28,6 @@
#include <android_bluetooth_sysprop.h>
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -1155,7 +1154,7 @@ void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr) {
}
BTM_LogHistory(kBtmLogTag, bd_addr, "Confirm reply",
- base::StringPrintf("status:%s", btm_status_text(res).c_str()));
+ std::format("status:{}", btm_status_text(res)));
btm_sec_cb.change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
@@ -2160,9 +2159,8 @@ tBTM_SEC_DEV_REC* btm_rnr_add_name_to_security_record(const RawAddress* p_bd_add
p_bd_name = (const uint8_t*)kBtmBdNameEmpty;
}
- BTM_LogHistory(
- kBtmLogTag, (p_bd_addr) ? *p_bd_addr : RawAddress::kEmpty, "RNR complete",
- base::StringPrintf("hci_status:%s name:%s", hci_error_code_text(hci_status).c_str(),
+ BTM_LogHistory(kBtmLogTag, (p_bd_addr) ? *p_bd_addr : RawAddress::kEmpty, "RNR complete",
+ std::format("hci_status:{} name:{}", hci_error_code_text(hci_status),
PRIVATE_NAME(reinterpret_cast<char const*>(p_bd_name))));
if (p_dev_rec == nullptr) {
@@ -2217,7 +2215,7 @@ tBTM_SEC_DEV_REC* btm_rnr_add_name_to_security_record(const RawAddress* p_bd_add
void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, const uint8_t* p_bd_name,
tHCI_STATUS hci_status) {
log::info("btm_sec_rmt_name_request_complete for {}",
- p_bd_addr ? ADDRESS_TO_LOGGABLE_CSTR(*p_bd_addr) : "null");
+ p_bd_addr ? p_bd_addr->ToRedactedStringForLogging() : "null");
if ((!p_bd_addr && !get_btm_client_interface().peer.BTM_IsAclConnectionUp(
btm_sec_cb.connecting_bda, BT_TRANSPORT_BR_EDR)) ||
@@ -2231,9 +2229,8 @@ void btm_sec_rmt_name_request_complete(const RawAddress* p_bd_addr, const uint8_
if (p_dev_rec == nullptr) {
log::warn(
"Remote read request complete for unknown device peer:{} "
- "pairing_state:{} "
- "hci_status:{} name:{}",
- (p_bd_addr) ? ADDRESS_TO_LOGGABLE_CSTR(*p_bd_addr) : "null",
+ "pairing_state:{} hci_status:{} name:{}",
+ p_bd_addr ? p_bd_addr->ToRedactedStringForLogging() : "null",
tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state),
hci_status_code_text(hci_status), reinterpret_cast<char const*>(p_bd_name));
return;
@@ -3229,6 +3226,11 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_en
if (transport == BT_TRANSPORT_LE) {
key_size = p_dev_rec->sec_rec.ble_keys.key_size;
+ if (key_size == 0 && status == HCI_SUCCESS && encr_enable == HCI_ENCRYPT_MODE_ON) {
+ /* Only case when key size is 0 during successfull encryption is pairing - for this case look
+ * up the key size */
+ key_size = SMP_GetPendingPairingKeySize();
+ }
}
log::debug(
@@ -3283,16 +3285,15 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_en
kBtmLogTag,
(transport == BT_TRANSPORT_LE) ? p_dev_rec->ble.pseudo_addr : p_dev_rec->bd_addr,
(status == HCI_SUCCESS) ? "Encryption success" : "Encryption failed",
- base::StringPrintf("status:%s transport:%s is_encrypted:%c",
- hci_status_code_text(status).c_str(),
- bt_transport_text(transport).c_str(), is_encrypted ? 'T' : 'F'));
+ std::format("status:{} transport:{} is_encrypted:{:c}", hci_status_code_text(status),
+ bt_transport_text(transport), is_encrypted ? 'T' : 'F'));
log::debug("after update p_dev_rec->sec_rec.sec_flags=0x{:x}", p_dev_rec->sec_rec.sec_flags);
btm_sec_check_pending_enc_req(p_dev_rec, transport, encr_enable);
if (!from_key_refresh) {
- bta_dm_on_encryption_change(bt_encryption_change_evt{p_dev_rec->ble.pseudo_addr, status,
+ bta_dm_on_encryption_change(bt_encryption_change_evt{p_dev_rec->bd_addr, status,
(bool)encr_enable, key_size, transport,
p_dev_rec->SupportsSecureConnections()});
}
@@ -3730,10 +3731,10 @@ void btm_sec_connected(const RawAddress& bda, uint16_t handle, tHCI_STATUS statu
l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, true);
}
log::info("Connection complete during pairing process peer:{}", bda);
- BTM_LogHistory(kBtmLogTag, bda, "Dedicated bonding",
- base::StringPrintf("Initiated:%c pairing_flag:0x%02x",
- (is_pair_flags_we_started_dd) ? 'T' : 'F',
- p_dev_rec->sec_rec.sec_flags));
+ BTM_LogHistory(
+ kBtmLogTag, bda, "Dedicated bonding",
+ std::format("Initiated:{:c} pairing_flag:0x{:02x}",
+ (is_pair_flags_we_started_dd) ? 'T' : 'F', p_dev_rec->sec_rec.sec_flags));
}
p_dev_rec->hci_handle = handle;
@@ -4513,6 +4514,14 @@ tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
}
if (start_auth) {
+ if (com::android::bluetooth::flags::ignore_auth_req_when_collision_timer_active() &&
+ alarm_is_scheduled(btm_sec_cb.sec_collision_timer) &&
+ (btm_sec_cb.p_collided_dev_rec->bd_addr == p_dev_rec->bd_addr)) {
+ log::debug(
+ "Security Manager: Authentication will be executed after collision "
+ "timer expired");
+ return tBTM_STATUS::BTM_CMD_STARTED;
+ }
log::debug("Security Manager: Start authentication");
/*
@@ -4736,8 +4745,8 @@ void tBTM_SEC_CB::change_pairing_state(tBTM_PAIRING_STATE new_state) {
if (pairing_state != new_state) {
BTM_LogHistory(kBtmLogTag, btm_sec_cb.pairing_bda, "Pairing state changed",
- base::StringPrintf("%s => %s", tBTM_SEC_CB::btm_pair_state_descr(pairing_state),
- tBTM_SEC_CB::btm_pair_state_descr(new_state)));
+ std::format("{} => {}", tBTM_SEC_CB::btm_pair_state_descr(pairing_state),
+ tBTM_SEC_CB::btm_pair_state_descr(new_state)));
}
pairing_state = new_state;
diff --git a/system/stack/btm/security_device_record.h b/system/stack/btm/security_device_record.h
index d72e1c078b..94e48753d2 100644
--- a/system/stack/btm/security_device_record.h
+++ b/system/stack/btm/security_device_record.h
@@ -18,7 +18,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -292,18 +291,13 @@ public:
void increment_sign_counter(bool local);
std::string ToString() const {
- return base::StringPrintf(
- "bredr_linkkey_known:%c,le_linkkey_known:%c,"
- "bond_type:%s,"
- "bredr_linkkey_type:%s,"
- "ble_enc_key_size:%d,"
- "bredr_authenticated:%c,le_authenticated:%c,"
- "16_digit_key_authenticated:%c,"
- "bredr_encrypted:%c,le_encrypted:%c",
+ return std::format(
+ "bredr_linkkey_known:{:c},le_linkkey_known:{:c},bond_type:{},bredr_linkkey_type:{},ble_"
+ "enc_key_size:{},bredr_authenticated:{:c},le_authenticated:{:c},16_digit_key_"
+ "authenticated:{:c},bredr_encrypted:{:c},le_encrypted:{:c}",
is_link_key_known() ? 'T' : 'F', is_le_link_key_known() ? 'T' : 'F',
- bond_type_text(bond_type).c_str(), linkkey_type_text(link_key_type).c_str(),
- enc_key_size, is_device_authenticated() ? 'T' : 'F',
- is_le_device_authenticated() ? 'T' : 'F',
+ bond_type_text(bond_type), linkkey_type_text(link_key_type), enc_key_size,
+ is_device_authenticated() ? 'T' : 'F', is_le_device_authenticated() ? 'T' : 'F',
is_le_link_16_digit_key_authenticated() ? 'T' : 'F', is_device_encrypted() ? 'T' : 'F',
is_le_device_encrypted() ? 'T' : 'F');
}
@@ -331,13 +325,12 @@ public:
bool SupportsSecureConnections() const { return remote_supports_secure_connections; }
std::string ToString() const {
- return base::StringPrintf(
- "%s %6s cod:%s remote_info:%-14s sm4:0x%02x SecureConn:%c name:\"%s\""
- "sec_prop:%s",
- ADDRESS_TO_LOGGABLE_CSTR(bd_addr), DeviceTypeText(device_type).c_str(),
- dev_class_text(dev_class).c_str(), remote_version_info.ToString().c_str(), sm4,
- (remote_supports_secure_connections) ? 'T' : 'F',
- PRIVATE_NAME(reinterpret_cast<char const*>(sec_bd_name)), sec_rec.ToString().c_str());
+ return std::format(
+ "{} {:6s} cod:{} remote_info:{:<14s} sm4:0x{:02x} SecureConn:{:c} "
+ "name:\"{}\" sec_prop:{}",
+ bd_addr, DeviceTypeText(device_type), dev_class_text(dev_class),
+ remote_version_info.ToString(), sm4, remote_supports_secure_connections ? 'T' : 'F',
+ PRIVATE_NAME(reinterpret_cast<char const*>(sec_bd_name)), sec_rec.ToString());
}
public:
diff --git a/system/stack/connection_manager/connection_manager.cc b/system/stack/connection_manager/connection_manager.cc
index c29ac5d403..11d4637b56 100644
--- a/system/stack/connection_manager/connection_manager.cc
+++ b/system/stack/connection_manager/connection_manager.cc
@@ -27,7 +27,9 @@
#include <memory>
#include <set>
+#include "gd/hci/controller_interface.h"
#include "main/shim/acl_api.h"
+#include "main/shim/entry.h"
#include "main/shim/le_scanning_manager.h"
#include "os/logging/log_adapter.h"
#include "osi/include/alarm.h"
@@ -42,9 +44,6 @@
#define DIRECT_CONNECT_TIMEOUT (30 * 1000) /* 30 seconds */
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
constexpr char kBtmLogTag[] = "TA";
@@ -62,8 +61,8 @@ static void alarm_closure_cb(void* p) {
}
// Periodic alarms are not supported, because we clean up data in callback
-void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm, uint64_t interval_ms,
- base::OnceClosure user_task) {
+static void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm,
+ uint64_t interval_ms, base::OnceClosure user_task) {
closure_data* data = new closure_data;
data->posted_from = posted_from;
data->user_task = std::move(user_task);
@@ -108,17 +107,45 @@ bool is_anyone_connecting(const std::map<RawAddress, tAPPS_CONNECTING>::iterator
!it->second.doing_targeted_announcements_conn.empty();
}
+static bool accept_list_is_full() {
+ uint8_t accept_list_size = shim::GetController()->GetLeFilterAcceptListSize();
+
+ int num_entries = 0;
+ for (const auto& entry : bgconn_dev) {
+ if (entry.second.is_in_accept_list) {
+ num_entries++;
+ }
+ }
+
+ if (num_entries >= accept_list_size) {
+ return true;
+ }
+
+ return false;
+}
+
} // namespace
-/** background connection device from the list. Returns pointer to the device
- * record, or nullptr if not found */
+/** Return all apps interested in device, or empty set if not found. */
std::set<tAPP_ID> get_apps_connecting_to(const RawAddress& address) {
log::debug("address={}", address);
auto it = bgconn_dev.find(address);
- return (it != bgconn_dev.end()) ? it->second.doing_bg_conn : std::set<tAPP_ID>();
+ if (it == bgconn_dev.end()) {
+ return std::set<tAPP_ID>();
+ }
+
+ std::set<tAPP_ID> result;
+ result.insert(it->second.doing_bg_conn.begin(), it->second.doing_bg_conn.end());
+ result.insert(it->second.doing_targeted_announcements_conn.begin(),
+ it->second.doing_targeted_announcements_conn.end());
+
+ for (const auto& entry : it->second.doing_direct_conn) {
+ result.insert(entry.first);
+ }
+ return result;
}
-bool IsTargetedAnnouncement(const uint8_t* p_eir, uint16_t eir_len) {
+static bool IsTargetedAnnouncement(const uint8_t* p_eir, uint16_t eir_len) {
const uint8_t* p_service_data = p_eir;
uint8_t service_data_len = 0;
@@ -186,7 +213,7 @@ static void target_announcement_observe_results_cb(tBTM_INQ_RESULTS* p_inq, cons
do_in_main_thread(base::BindOnce(schedule_direct_connect_add, app_id, addr));
}
-void target_announcements_filtering_set(bool enable) {
+static void target_announcements_filtering_set(bool enable) {
log::debug("enable {}", enable);
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, (enable ? "Start filtering" : "Stop filtering"));
@@ -276,6 +303,12 @@ bool background_connect_add(uint8_t app_id, const RawAddress& address) {
if (is_targeted_announcement_enabled) {
log::debug("Targeted announcement enabled, do not add to AcceptList");
} else {
+ if (accept_list_is_full()) {
+ log::warn("accept list is full ({}), can't add {}",
+ shim::GetController()->GetLeFilterAcceptListSize(), address);
+ return false;
+ }
+
if (!bluetooth::shim::ACL_AcceptLeConnectionFrom(BTM_Sec_GetAddressWithType(address),
false)) {
log::warn("Failed to add device {} to accept list for app {}", address,
@@ -431,7 +464,7 @@ void reset(bool after_reset) {
}
}
-void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) {
+static void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) {
log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
on_connection_timed_out(app_id, address);
@@ -458,57 +491,65 @@ static void find_in_device_record(const RawAddress& bd_addr, tBLE_BD_ADDR* addre
return;
}
-bool create_le_connection(uint8_t /* id */, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) {
+bool direct_connect_add(uint8_t app_id, const RawAddress& address, tBLE_ADDR_TYPE addr_type) {
tBLE_BD_ADDR address_with_type{
.type = addr_type,
- .bda = bd_addr,
+ .bda = address,
};
- find_in_device_record(bd_addr, &address_with_type);
-
- log::debug("Creating le direct connection to:{} type:{} (initial type: {})", address_with_type,
- AddressTypeText(address_with_type.type), AddressTypeText(addr_type));
+ find_in_device_record(address, &address_with_type);
if (address_with_type.type == BLE_ADDR_ANONYMOUS) {
- log::warn(
- "Creating le direct connection to:{}, address type 'anonymous' is "
- "invalid",
- address_with_type);
+ log::warn("Can't use anonymous address for connection: {}", address_with_type);
return false;
}
- bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type,
- /* is_direct */ true);
- return true;
-}
+ log::debug("app_id=0x{:x}, address={} (initial type: {})", static_cast<int>(app_id),
+ address_with_type, AddressTypeText(addr_type));
-/** Add a device to the direct connection list. Returns true if device
- * added to the list, false otherwise */
-bool direct_connect_add(uint8_t app_id, const RawAddress& address) {
- log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
bool in_acceptlist = false;
auto it = bgconn_dev.find(address);
if (it != bgconn_dev.end()) {
+ const tAPPS_CONNECTING& info = it->second;
// app already trying to connect to this particular device
- if (it->second.doing_direct_conn.count(app_id)) {
- log::info("direct connect attempt from app_id=0x{:x} already in progress", app_id);
+ if (info.doing_direct_conn.count(app_id)) {
+ log::info("attempt from app_id=0x{:x} to {} already in progress", app_id, address_with_type);
return false;
}
+ // This is to match existing GD connection manager behavior - if multiple apps try direct
+ // connect at same time, only 1st request is fully processed
+ if (!info.doing_direct_conn.empty()) {
+ log::info("app_id=0x{:x}: attempt from other app already in progress, will merge {}", app_id,
+ address_with_type);
+ return true;
+ }
+
// are we already in the acceptlist ?
- if (it->second.is_in_accept_list) {
- log::warn("Background connection attempt already in progress app_id={:x}", app_id);
+ if (info.is_in_accept_list) {
+ log::warn("background connect attempt already in progress app_id=0x{:x} {}", app_id,
+ address_with_type);
in_acceptlist = true;
}
}
if (!in_acceptlist) {
- if (!bluetooth::shim::ACL_AcceptLeConnectionFrom(BTM_Sec_GetAddressWithType(address), true)) {
+ if (accept_list_is_full()) {
+ log::warn("accept list is full ({}), can't add {}",
+ shim::GetController()->GetLeFilterAcceptListSize(), address_with_type);
+ return false;
+ }
+
+ if (!bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type, true /* is_direct */)) {
// if we can't add to acceptlist, turn parameters back to slow.
- log::warn("Unable to add le device to acceptlist");
+ log::warn("unable to add to acceptlist {}", address_with_type);
return false;
}
bgconn_dev[address].is_in_accept_list = true;
+ } else {
+ // if already in accept list, we should just bump parameters up for direct
+ // connection. There is no API for that yet, so use API that's adding to accept list.
+ bluetooth::shim::ACL_AcceptLeConnectionFrom(address_with_type, true /* is_direct */);
}
// Setup a timer
@@ -517,7 +558,6 @@ bool direct_connect_add(uint8_t app_id, const RawAddress& address) {
base::BindOnce(&wl_direct_connect_timeout_cb, app_id, address));
bgconn_dev[address].doing_direct_conn.emplace(app_id, unique_alarm_ptr(timeout, &alarm_free));
-
return true;
}
@@ -529,13 +569,13 @@ bool direct_connect_remove(uint8_t app_id, const RawAddress& address, bool conne
log::debug("app_id={}, address={}", static_cast<int>(app_id), address);
auto it = bgconn_dev.find(address);
if (it == bgconn_dev.end()) {
- log::warn("Unable to find background connection to remove peer:{}", address);
+ log::warn("unable to find entry to remove: {}", address);
return false;
}
auto app_it = it->second.doing_direct_conn.find(app_id);
if (app_it == it->second.doing_direct_conn.end()) {
- log::warn("Unable to find direct connection to remove peer:{}", address);
+ log::warn("unable to find direct connection to remove: {}", address);
return false;
}
@@ -547,13 +587,12 @@ bool direct_connect_remove(uint8_t app_id, const RawAddress& address, bool conne
if (is_anyone_interested_to_use_accept_list(it)) {
if (connection_timeout) {
- /* In such case we need to add device back to allow list because,
- * when connection timeout out, the lower layer removes device from
- * the allow list.
+ /* In such case we need to add device back to allow list because, when connection timeout
+ * out, the lower layer removes device from the allow list.
*/
if (!bluetooth::shim::ACL_AcceptLeConnectionFrom(BTM_Sec_GetAddressWithType(address),
- false)) {
- log::warn("Failed to re-add device {} to accept list after connection timeout", address);
+ false /* is_direct */)) {
+ log::warn("Failed to re-add {} to accept list after connection timeout", address);
}
}
return true;
@@ -582,7 +621,7 @@ void dump(int fd) {
for (const auto& entry : bgconn_dev) {
// TODO: confirm whether we need to replace this
dprintf(fd, "\n\t * %s:\t\tin_accept_list: %s\t cap_targeted_announcements: %s",
- ADDRESS_TO_LOGGABLE_CSTR(entry.first),
+ entry.first.ToRedactedStringForLogging().c_str(),
entry.second.is_in_accept_list ? "true" : "false",
entry.second.doing_targeted_announcements_conn.empty() ? "false" : "true");
diff --git a/system/stack/connection_manager/connection_manager.h b/system/stack/connection_manager/connection_manager.h
index 4d86eae0e3..0f029fbe60 100644
--- a/system/stack/connection_manager/connection_manager.h
+++ b/system/stack/connection_manager/connection_manager.h
@@ -37,10 +37,22 @@ namespace connection_manager {
using tAPP_ID = uint8_t;
-/* for background connection */
+/* Mark device as using targeted announcements.
+ *
+ * @return true if device added to the list, false otherwise */
bool background_connect_targeted_announcement_add(tAPP_ID app_id, const RawAddress& address);
+
+/* Add a background connect request.
+ *
+ * @return true if device added to the list, false otherwise */
bool background_connect_add(tAPP_ID app_id, const RawAddress& address);
+
+/* Remove a background connection request.
+ *
+ * @return true if the request is removed, false otherwise.
+ */
bool background_connect_remove(tAPP_ID app_id, const RawAddress& address);
+
bool remove_unconditional(const RawAddress& address);
void reset(bool after_reset);
@@ -50,15 +62,15 @@ void on_connection_complete(const RawAddress& address);
std::set<tAPP_ID> get_apps_connecting_to(const RawAddress& remote_bda);
-/* create_le_connection is adding device directly to AclManager, and relying on it's "direct
- * connect" implementation.
- * direct_connect_add method is doing multiplexing of apps request, and
- * sending the request to AclManager, but it lacks some extra checks and lookups. Currently these
- * methods are exclusive, if you try to use both you will get some bad behavior. These should be
- * merged into one. */
-bool create_le_connection(uint8_t /* id */, const RawAddress& bd_addr,
- tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC);
-bool direct_connect_add(tAPP_ID app_id, const RawAddress& address);
+/* Add a direct connect request.
+ *
+ * @return true if device added to the list, false otherwise */
+bool direct_connect_add(tAPP_ID app_id, const RawAddress& address,
+ tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC);
+/* Remove a direct connection request.
+ *
+ * @return true if the request is removed, false otherwise.
+ */
bool direct_connect_remove(tAPP_ID app_id, const RawAddress& address,
bool connection_timeout = false);
diff --git a/system/stack/eatt/eatt.h b/system/stack/eatt/eatt.h
index 7a05f27b63..c47509def7 100644
--- a/system/stack/eatt/eatt.h
+++ b/system/stack/eatt/eatt.h
@@ -87,10 +87,12 @@ public:
if (state == EattChannelState::EATT_CHANNEL_OPENED) {
server_outstanding_cmd_ = tGATT_SR_CMD{};
char name[64];
- sprintf(name, "eatt_ind_ack_timer_%s_cid_0x%04x", ADDRESS_TO_LOGGABLE_CSTR(bda_), cid_);
+ sprintf(name, "eatt_ind_ack_timer_%s_cid_0x%04x", bda_.ToRedactedStringForLogging().c_str(),
+ cid_);
ind_ack_timer_ = alarm_new(name);
- sprintf(name, "eatt_ind_conf_timer_%s_cid_0x%04x", ADDRESS_TO_LOGGABLE_CSTR(bda_), cid_);
+ sprintf(name, "eatt_ind_conf_timer_%s_cid_0x%04x",
+ bda_.ToRedactedStringForLogging().c_str(), cid_);
ind_confirmation_timer_ = alarm_new(name);
}
}
@@ -99,6 +101,7 @@ public:
void EattChannelSetTxMTU(uint16_t tx_mtu) {
this->tx_mtu_ = std::min<uint16_t>(tx_mtu, EATT_MAX_TX_MTU);
+ this->tx_mtu_ = std::max<uint16_t>(tx_mtu, EATT_MIN_MTU_MPS);
}
};
diff --git a/system/stack/fuzzers/l2cap_fuzzer.cc b/system/stack/fuzzers/l2cap_fuzzer.cc
index 1963983aef..004e5b0920 100644
--- a/system/stack/fuzzers/l2cap_fuzzer.cc
+++ b/system/stack/fuzzers/l2cap_fuzzer.cc
@@ -78,6 +78,9 @@ uint32_t GetSystemPropertyUint32Base(const std::string& /*property*/, uint32_t d
int /*base*/) {
return default_value;
}
+uint32_t GetSystemPropertyUint32(const std::string& /*property*/, uint32_t default_value) {
+ return default_value;
+}
} // namespace os
namespace hal {
@@ -97,8 +100,8 @@ void SnoopLogger::SetL2capChannelOpen(uint16_t, uint16_t, uint16_t, uint16_t, bo
} // namespace bluetooth
namespace connection_manager {
-bool create_le_connection(uint8_t /* id */, const RawAddress& /* bd_addr */,
- tBLE_ADDR_TYPE /* addr_type */) {
+bool direct_connect_add(uint8_t /* id */, const RawAddress& /* bd_addr */,
+ tBLE_ADDR_TYPE /* addr_type */) {
return true;
}
} // namespace connection_manager
diff --git a/system/stack/fuzzers/rfcomm_fuzzer.cc b/system/stack/fuzzers/rfcomm_fuzzer.cc
index 3f3afbfe40..1445156aec 100644
--- a/system/stack/fuzzers/rfcomm_fuzzer.cc
+++ b/system/stack/fuzzers/rfcomm_fuzzer.cc
@@ -36,12 +36,18 @@
#include "test/mock/mock_stack_btm_dev.h"
#include "test/mock/mock_stack_l2cap_api.h"
#include "test/mock/mock_stack_l2cap_ble.h"
+#include "test/mock/mock_stack_l2cap_interface.h"
#include "test/rfcomm/stack_rfcomm_test_utils.h"
// TODO(b/369381361) Enfore -Wmissing-prototypes
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#pragma GCC diagnostic ignored "-Wunused-parameter"
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::Unused;
+
namespace bluetooth {
namespace hal {
class SnoopLogger;
@@ -75,30 +81,35 @@ void port_event_cback(uint32_t code, uint16_t port_handle) {
}
class FakeBtStack {
+ NiceMock<bluetooth::testing::stack::l2cap::Mock> mock_l2cap_interface;
+
public:
+ NiceMock<bluetooth::rfcomm::MockRfcommCallback> mock_rfcomm_callback;
+
FakeBtStack() {
- test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t lcid, BT_HDR* hdr) {
- osi_free(hdr);
- return tL2CAP_DW_RESULT::SUCCESS;
- };
- test::mock::stack_l2cap_api::L2CA_ConnectReq.body =
- [](uint16_t psm, const RawAddress& raw_address) { return kDummyCID; };
-
- test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t) { return true; };
- test::mock::stack_l2cap_api::L2CA_Register.body =
- [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
- tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu,
- uint16_t sec_level) {
- appl_info = p_cb_info;
- return psm;
- };
+ ON_CALL(mock_l2cap_interface, L2CA_DataWrite)
+ .WillByDefault([](Unused, BT_HDR* hdr) {
+ osi_free(hdr);
+ return tL2CAP_DW_RESULT::SUCCESS;
+ });
+ ON_CALL(mock_l2cap_interface, L2CA_ConnectReq)
+ .WillByDefault([](Unused, Unused) { return kDummyCID; });
+ ON_CALL(mock_l2cap_interface, L2CA_DisconnectReq)
+ .WillByDefault([](Unused) { return true; });
+ ON_CALL(mock_l2cap_interface, L2CA_Register)
+ .WillByDefault([](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, Unused, Unused,
+ Unused, Unused, Unused) {
+ appl_info = p_cb_info;
+ return psm;
+ });
+ bluetooth::testing::stack::l2cap::set_interface(&mock_l2cap_interface);
+
+ rfcomm_callback = &mock_rfcomm_callback;
}
~FakeBtStack() {
- test::mock::stack_l2cap_api::L2CA_DataWrite = {};
- test::mock::stack_l2cap_api::L2CA_ConnectReq = {};
- test::mock::stack_l2cap_api::L2CA_DisconnectReq = {};
- test::mock::stack_l2cap_api::L2CA_Register = {};
+ rfcomm_callback = nullptr;
+ bluetooth::testing::stack::l2cap::reset_interface();
}
};
@@ -108,15 +119,6 @@ public:
FakeBtStack fake_stack;
};
-class Mocks {
-public:
- ::testing::NiceMock<bluetooth::rfcomm::MockRfcommCallback> mock_rfcomm_callback;
-
- Mocks() { rfcomm_callback = &mock_rfcomm_callback; }
-
- ~Mocks() { rfcomm_callback = nullptr; }
-};
-
} // namespace
static int Cleanup(uint16_t* server_handle) { return RFCOMM_RemoveServer(*server_handle); }
@@ -129,7 +131,7 @@ static int ServerInit(FuzzedDataProvider* fdp, uint16_t* server_handle) {
auto uuid = fdp->ConsumeIntegral<uint16_t>();
int status = RFCOMM_CreateConnectionWithSecurity(uuid, scn, true, mtu, kDummyAddr, server_handle,
- port_mgmt_cback, 0);
+ port_mgmt_cback, 0, RfcommCfgInfo{});
if (status != PORT_SUCCESS) {
return status;
}
@@ -174,7 +176,7 @@ static int ClientInit(FuzzedDataProvider* fdp, uint16_t* client_handle) {
auto uuid = fdp->ConsumeIntegral<uint16_t>();
int status = RFCOMM_CreateConnectionWithSecurity(uuid, scn, false, mtu, kDummyAddr, client_handle,
- port_mgmt_cback, 0);
+ port_mgmt_cback, 0, RfcommCfgInfo{});
if (status != PORT_SUCCESS) {
return status;
}
@@ -212,7 +214,6 @@ static void FuzzAsClient(FuzzedDataProvider* fdp) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
auto fakes = std::make_unique<Fakes>();
- auto mocks = std::make_unique<Mocks>();
FuzzedDataProvider fdp(data, size);
diff --git a/system/stack/gap/gap_conn.cc b/system/stack/gap/gap_conn.cc
index fd988c8fd3..0f8ff9b77f 100644
--- a/system/stack/gap/gap_conn.cc
+++ b/system/stack/gap/gap_conn.cc
@@ -55,7 +55,9 @@ typedef struct {
uint8_t service_id; /* Used by BTM */
uint16_t gap_handle; /* GAP handle */
- uint16_t connection_id; /* L2CAP CID */
+ uint16_t local_cid; /* Local L2CAP CID */
+ uint16_t remote_cid; /* Remote L2CAP CID */
+ uint16_t acl_handle; /* ACL handle */
bool rem_addr_specified;
uint8_t chan_mode_mask; /* Supported channel modes (FCR) */
RawAddress rem_dev_address;
@@ -211,7 +213,12 @@ uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t service_id, bool is
/* Configure L2CAP COC, if transport is LE */
if (transport == BT_TRANSPORT_LE) {
- p_ccb->local_coc_cfg.credits = L2CA_LeCreditDefault();
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349376
+ p_ccb->local_coc_cfg.credits =
+ (p_ccb->cfg.init_credit_present) ? p_ccb->cfg.init_credit : L2CA_LeCreditDefault();
+ } else {
+ p_ccb->local_coc_cfg.credits = L2CA_LeCreditDefault();
+ }
p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
uint16_t max_mps = bluetooth::shim::GetController()->GetLeBufferSize().le_data_packet_length_;
@@ -284,7 +291,7 @@ uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t service_id, bool is
cid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(p_ccb->psm, *p_rem_bda,
security);
if (cid != 0) {
- p_ccb->connection_id = cid;
+ p_ccb->local_cid = cid;
return p_ccb->gap_handle;
}
log::warn("Unable to initiate connection peer:{} psm:{} transport:{}", *p_rem_bda, p_ccb->psm,
@@ -295,7 +302,7 @@ uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t service_id, bool is
cid = stack::l2cap::get_interface().L2CA_ConnectLECocReq(p_ccb->psm, *p_rem_bda,
&p_ccb->local_coc_cfg, security);
if (cid != 0) {
- p_ccb->connection_id = cid;
+ p_ccb->local_cid = cid;
return p_ccb->gap_handle;
}
log::warn("Unable to initiate connection peer:{} psm:{} transport:{}", *p_rem_bda, p_ccb->psm,
@@ -329,14 +336,14 @@ uint16_t GAP_ConnClose(uint16_t gap_handle) {
/* Check if we have a connection ID */
if (p_ccb->con_state != GAP_CCB_STATE_LISTENING) {
if (p_ccb->transport == BT_TRANSPORT_LE) {
- if (!stack::l2cap::get_interface().L2CA_DisconnectLECocReq(p_ccb->connection_id)) {
+ if (!stack::l2cap::get_interface().L2CA_DisconnectLECocReq(p_ccb->local_cid)) {
log::warn("Unable to request L2CAP disconnect le_coc peer:{} cid:{}",
- p_ccb->rem_dev_address, p_ccb->connection_id);
+ p_ccb->rem_dev_address, p_ccb->local_cid);
}
} else {
- if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_ccb->connection_id)) {
+ if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_ccb->local_cid)) {
log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_ccb->rem_dev_address,
- p_ccb->connection_id);
+ p_ccb->local_cid);
}
}
}
@@ -451,9 +458,9 @@ static bool gap_try_write_queued_data(tGAP_CCB* p_ccb) {
while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
tL2CAP_DW_RESULT status;
if (p_ccb->transport == BT_TRANSPORT_LE) {
- status = stack::l2cap::get_interface().L2CA_LECocDataWrite(p_ccb->connection_id, p_buf);
+ status = stack::l2cap::get_interface().L2CA_LECocDataWrite(p_ccb->local_cid, p_buf);
} else {
- status = stack::l2cap::get_interface().L2CA_DataWrite(p_ccb->connection_id, p_buf);
+ status = stack::l2cap::get_interface().L2CA_DataWrite(p_ccb->local_cid, p_buf);
}
if (status == tL2CAP_DW_RESULT::CONGESTED) {
@@ -576,7 +583,67 @@ uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle) {
return 0;
}
- return p_ccb->connection_id;
+ return p_ccb->local_cid;
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_GetLeChannelInfo
+ *
+ * Description This function is called to get LE L2CAP channel information
+ * by the gap handle. All OUT parameters must NOT be nullptr.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * remote_mtu - OUT remote L2CAP MTU
+ * local_mps - OUT local L2CAP COC MPS
+ * remote_mps - OUT remote L2CAP COC MPS
+ * local_credit - OUT local L2CAP COC credit
+ * remote_credit - OUT remote L2CAP COC credit
+ * local_cid - OUT local L2CAP CID
+ * remote_cid - OUT remote L2CAP CID
+ * acl_handle - OUT ACL handle
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_GetLeChannelInfo(uint16_t gap_handle, uint16_t* remote_mtu, uint16_t* local_mps,
+ uint16_t* remote_mps, uint16_t* local_credit, uint16_t* remote_credit,
+ uint16_t* local_cid, uint16_t* remote_cid, uint16_t* acl_handle) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL || p_ccb->transport != BT_TRANSPORT_LE ||
+ p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+ return false;
+ }
+
+ *remote_mtu = p_ccb->peer_coc_cfg.mtu;
+ *local_mps = p_ccb->local_coc_cfg.mps;
+ *remote_mps = p_ccb->peer_coc_cfg.mps;
+ *local_credit = p_ccb->local_coc_cfg.credits;
+ *remote_credit = p_ccb->peer_coc_cfg.credits;
+ *local_cid = p_ccb->local_cid;
+ *remote_cid = p_ccb->remote_cid;
+ *acl_handle = p_ccb->acl_handle;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_IsTransportLe
+ *
+ * Description This function returns if the transport is LE by the gap handle.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ *
+ * Returns true if transport is LE, else false
+ *
+ ******************************************************************************/
+bool GAP_IsTransportLe(uint16_t gap_handle) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL || p_ccb->transport != BT_TRANSPORT_LE ||
+ p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+ return false;
+ }
+ return true;
}
/*******************************************************************************
@@ -649,7 +716,7 @@ static void gap_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid, uint1
/* Save the BD Address and Channel ID. */
p_ccb->rem_dev_address = bd_addr;
- p_ccb->connection_id = l2cap_cid;
+ p_ccb->local_cid = l2cap_cid;
if (p_ccb->transport == BT_TRANSPORT_LE) {
/* get the remote coc configuration */
@@ -683,12 +750,16 @@ static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
tGAP_CB_DATA cb_data;
uint16_t l2cap_remote_cid;
if (com::android::bluetooth::flags::bt_socket_api_l2cap_cid() &&
- stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_ccb->connection_id,
+ stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_ccb->local_cid,
&l2cap_remote_cid)) {
- cb_data.l2cap_cids.local_cid = p_ccb->connection_id;
+ cb_data.l2cap_cids.local_cid = p_ccb->local_cid;
cb_data.l2cap_cids.remote_cid = l2cap_remote_cid;
cb_data_ptr = &cb_data;
}
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3367197
+ stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_ccb->local_cid, &p_ccb->remote_cid);
+ stack::l2cap::get_interface().L2CA_GetAclHandle(p_ccb->local_cid, &p_ccb->acl_handle);
+ }
p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED, cb_data_ptr);
@@ -926,7 +997,7 @@ static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
* Function gap_find_ccb_by_cid
*
* Description This function searches the CCB table for an entry with the
- * passed CID.
+ * passed local CID.
*
* Returns the CCB address, or NULL if not found.
*
@@ -937,7 +1008,7 @@ static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid) {
/* Look through each connection control block */
for (xx = 0, p_ccb = conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
- if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid)) {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->local_cid == cid)) {
return p_ccb;
}
}
diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc
index 3f2c7136a9..19ea3a3090 100644
--- a/system/stack/gatt/gatt_api.cc
+++ b/system/stack/gatt/gatt_api.cc
@@ -33,6 +33,7 @@
#include "internal_include/bt_target.h"
#include "internal_include/stack_config.h"
+#include "main/shim/helpers.h"
#include "os/system_properties.h"
#include "osi/include/allocator.h"
#include "stack/arbiter/acl_arbiter.h"
@@ -47,6 +48,7 @@
#include "stack/include/l2cap_interface.h"
#include "stack/include/l2cdefs.h"
#include "stack/include/sdp_api.h"
+#include "stack/include/stack_metrics_logging.h"
#include "types/bluetooth/uuid.h"
#include "types/bt_transport.h"
#include "types/raw_address.h"
@@ -1472,6 +1474,8 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE ad
return true;
}
+ log_le_connection_lifecycle(ToGdAddress(bd_addr), true /* is_connect */, is_direct);
+
bool ret = false;
if (is_direct) {
log::debug("Starting direct connect gatt_if={} address={} transport={}", gatt_if, bd_addr,
@@ -1490,7 +1494,7 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE ad
log::warn("{} already added to gatt_if {} direct conn list", bd_addr, gatt_if);
}
- ret = connection_manager::create_le_connection(gatt_if, bd_addr, addr_type);
+ ret = connection_manager::direct_connect_add(gatt_if, bd_addr, addr_type);
}
} else {
@@ -1619,6 +1623,9 @@ tGATT_STATUS GATT_Disconnect(tCONN_ID conn_id) {
return GATT_ILLEGAL_PARAMETER;
}
+ log_le_connection_lifecycle(ToGdAddress(p_tcb->peer_bda), true /* is_connect */,
+ false /* is_direct */);
+
tGATT_IF gatt_if = gatt_get_gatt_if(conn_id);
gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
return GATT_SUCCESS;
diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h
index 3999ec4638..db0d0da9ca 100644
--- a/system/stack/gatt/gatt_int.h
+++ b/system/stack/gatt/gatt_int.h
@@ -20,7 +20,6 @@
#define GATT_INT_H
#include <base/functional/bind.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <deque>
@@ -64,7 +63,7 @@ inline std::string gatt_security_action_text(const tGATT_SEC_ACTION& action) {
CASE_RETURN_TEXT(GATT_SEC_ENCRYPT_MITM);
CASE_RETURN_TEXT(GATT_SEC_ENC_PENDING);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", action);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(action));
}
}
@@ -248,7 +247,7 @@ inline std::string gatt_channel_state_text(const tGATT_CH_STATE& state) {
CASE_RETURN_TEXT(GATT_CH_CFG);
CASE_RETURN_TEXT(GATT_CH_OPEN);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", state);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(state));
}
}
@@ -473,8 +472,7 @@ inline std::string EpochMillisToString(uint64_t time_ms) {
struct tm tm;
localtime_r(&time_sec, &tm);
std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm);
- return base::StringPrintf("%s.%03u", s.c_str(),
- static_cast<unsigned int>(time_ms % MillisPerSecond));
+ return std::format("{}.{:03}", s, time_ms % MillisPerSecond);
}
} // namespace
@@ -484,9 +482,8 @@ struct tTCB_STATE_HISTORY {
tGATT_CH_STATE state;
std::string holders_info;
std::string ToString() const {
- return base::StringPrintf("%s, %s, state: %s, %s", ADDRESS_TO_LOGGABLE_CSTR(address),
- bt_transport_text(transport).c_str(),
- gatt_channel_state_text(state).c_str(), holders_info.c_str());
+ return std::format("{}, {}, state: {}, {}", address, bt_transport_text(transport),
+ gatt_channel_state_text(state), holders_info);
}
};
diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc
index e530d9fd5e..0d8d51d846 100644
--- a/system/stack/gatt/gatt_main.cc
+++ b/system/stack/gatt/gatt_main.cc
@@ -235,7 +235,7 @@ static bool gatt_connect(const RawAddress& rem_bda, tBLE_ADDR_TYPE addr_type, tG
}
p_tcb->att_lcid = L2CAP_ATT_CID;
- return connection_manager::create_le_connection(gatt_if, rem_bda, addr_type);
+ return connection_manager::direct_connect_add(gatt_if, rem_bda, addr_type);
}
/*******************************************************************************
diff --git a/system/stack/gatt/gatt_sr.cc b/system/stack/gatt/gatt_sr.cc
index aad7b1f89e..49c1ae452d 100644
--- a/system/stack/gatt/gatt_sr.cc
+++ b/system/stack/gatt/gatt_sr.cc
@@ -162,6 +162,13 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) {
uint8_t* p;
bool is_overflow = false;
+ // We need at least one extra byte for the opcode
+ if (mtu == 0) {
+ log::error("Invalid MTU");
+ p_cmd->status = GATT_ILLEGAL_PARAMETER;
+ return;
+ }
+
len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu;
BT_HDR* p_buf = (BT_HDR*)osi_calloc(len);
p_buf->offset = L2CAP_MIN_OFFSET;
@@ -423,8 +430,19 @@ static void gatt_process_exec_write_req(tGATT_TCB& tcb, uint16_t cid, uint8_t op
}
}
} else { /* nothing needs to be executed , send response now */
- log::error("gatt_process_exec_write_req: no prepare write pending");
- gatt_send_error_rsp(tcb, cid, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+ log::warn("gatt_process_exec_write_req: no prepare write pending");
+ if (com::android::bluetooth::flags::fix_execute_write_no_pending()) {
+ uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid);
+ BT_HDR* p_buf =
+ attp_build_sr_msg(tcb, GATT_RSP_EXEC_WRITE, (tGATT_SR_MSG*)NULL, payload_size);
+ if (p_buf != NULL) {
+ attp_send_sr_msg(tcb, cid, p_buf);
+ } else {
+ gatt_send_error_rsp(tcb, cid, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+ }
+ } else {
+ gatt_send_error_rsp(tcb, cid, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+ }
}
}
@@ -761,6 +779,11 @@ static void gatts_process_primary_service_req(tGATT_TCB& tcb, uint16_t cid, uint
uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid);
+ // This can happen if the channel is already closed.
+ if (payload_size == 0) {
+ return;
+ }
+
uint16_t msg_len = (uint16_t)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
BT_HDR* p_msg = (BT_HDR*)osi_calloc(msg_len);
reason = gatt_build_primary_service_rsp(p_msg, tcb, cid, op_code, s_hdl, e_hdl, p_data, value);
@@ -793,6 +816,12 @@ static void gatts_process_find_info(tGATT_TCB& tcb, uint16_t cid, uint8_t op_cod
}
uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid);
+
+ // This can happen if the channel is already closed.
+ if (payload_size == 0) {
+ return;
+ }
+
uint16_t buf_len = (uint16_t)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
BT_HDR* p_msg = (BT_HDR*)osi_calloc(buf_len);
@@ -938,6 +967,11 @@ static void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint16_t cid, uint8_t
uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid);
+ // This can happen if the channel is already closed.
+ if (payload_size == 0) {
+ return;
+ }
+
size_t msg_len = sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET;
BT_HDR* p_msg = (BT_HDR*)osi_calloc(msg_len);
uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
@@ -1085,6 +1119,11 @@ static void gatts_process_read_req(tGATT_TCB& tcb, uint16_t cid, tGATT_SRV_LIST_
uint8_t* p_data) {
uint16_t payload_size = gatt_tcb_get_payload_size(tcb, cid);
+ // This can happen if the channel is already closed.
+ if (payload_size == 0) {
+ return;
+ }
+
size_t buf_len = sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET;
uint16_t offset = 0;
diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc
index 73880e3cd4..88ecfe2d53 100644
--- a/system/stack/gatt/gatt_utils.cc
+++ b/system/stack/gatt/gatt_utils.cc
@@ -23,7 +23,6 @@
******************************************************************************/
#define LOG_TAG "gatt_utils"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -473,7 +472,7 @@ void gatt_tcb_dump(int fd) {
if (p_tcb->in_use) {
in_use_cnt++;
stream << " id: " << +p_tcb->tcb_idx
- << " address: " << ADDRESS_TO_LOGGABLE_STR(p_tcb->peer_bda)
+ << " address: " << p_tcb->peer_bda.ToRedactedStringForLogging()
<< " transport: " << bt_transport_text(p_tcb->transport)
<< " ch_state: " << gatt_channel_state_text(p_tcb->ch_state) << ", "
<< gatt_tcb_get_holders_info_string(p_tcb) << "\n";
diff --git a/system/stack/hid/hid_conn.h b/system/stack/hid/hid_conn.h
index 1611db4ffe..92175fcd26 100644
--- a/system/stack/hid/hid_conn.h
+++ b/system/stack/hid/hid_conn.h
@@ -25,7 +25,6 @@
#ifndef HID_CONN_H
#define HID_CONN_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include "macros.h"
@@ -56,7 +55,7 @@ typedef struct hid_conn {
CASE_RETURN_TEXT(HID_CONN_STATE_DISCONNECTING);
CASE_RETURN_TEXT(HID_CONN_STATE_SECURITY);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", state);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(state));
}
}
diff --git a/system/stack/hid/hidh_api.cc b/system/stack/hid/hidh_api.cc
index a02af75063..97d811ed5b 100644
--- a/system/stack/hid/hidh_api.cc
+++ b/system/stack/hid/hidh_api.cc
@@ -49,9 +49,6 @@
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
using namespace bluetooth::legacy::stack::sdp;
using bluetooth::Uuid;
@@ -95,7 +92,7 @@ tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr, tSDP_DISCOVERY_DB* p_db
}
}
-void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len, char* str) {
+static void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len, char* str) {
tSDP_DISC_ATTR* p_attr;
uint16_t name_len;
diff --git a/system/stack/hid/hidh_conn.cc b/system/stack/hid/hidh_conn.cc
index cc2a480b57..83bb039173 100644
--- a/system/stack/hid/hidh_conn.cc
+++ b/system/stack/hid/hidh_conn.cc
@@ -23,7 +23,6 @@
******************************************************************************/
#include <base/functional/callback.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
#include <string.h>
@@ -203,10 +202,9 @@ static void hidh_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid
tHID_CONN* p_hcon = &hh_cb.devices[i].conn;
- BTM_LogHistory(
- kBtmLogTag, hh_cb.devices[i].addr, "Connect request",
- base::StringPrintf("%s state:%s", (psm == HID_PSM_CONTROL) ? "control" : "interrupt",
- hid_conn::state_text(p_hcon->conn_state).c_str()));
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[i].addr, "Connect request",
+ std::format("{} state:{}", (psm == HID_PSM_CONTROL) ? "control" : "interrupt",
+ hid_conn::state_text(p_hcon->conn_state)));
/* Check we are in the correct state for this */
if (psm == HID_PSM_INTERRUPT) {
@@ -360,10 +358,9 @@ static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, tL2CAP_CONN result) {
} else {
p_hcon->conn_state = HID_CONN_STATE_CONFIG;
}
- BTM_LogHistory(
- kBtmLogTag, hh_cb.devices[dhandle].addr, "Configuring",
- base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s", p_hcon->ctrl_cid,
- p_hcon->intr_cid, hid_conn::state_text(p_hcon->conn_state).c_str()));
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Configuring",
+ std::format("control:0x{:04x} interrupt:0x{:04x} state:{}", p_hcon->ctrl_cid,
+ p_hcon->intr_cid, hid_conn::state_text(p_hcon->conn_state)));
return;
}
@@ -469,10 +466,9 @@ static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t /* initiator */,
hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL);
- BTM_LogHistory(
- kBtmLogTag, hh_cb.devices[dhandle].addr, "Connected",
- base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s", p_hcon->ctrl_cid,
- p_hcon->intr_cid, hid_conn::state_text(p_hcon->conn_state).c_str()));
+ BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connected",
+ std::format("control:0x{:04x} interrupt:0x{:04x} state:{}", p_hcon->ctrl_cid,
+ p_hcon->intr_cid, hid_conn::state_text(p_hcon->conn_state)));
}
}
@@ -506,9 +502,9 @@ static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
log::verbose("HID-Host Rcvd L2CAP disc, CID: 0x{:x}", l2cap_cid);
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
- BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
- base::StringPrintf("%s channel",
- (l2cap_cid == p_hcon->ctrl_cid) ? "control" : "interrupt"));
+ BTM_LogHistory(
+ kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
+ std::format("{} channel", (l2cap_cid == p_hcon->ctrl_cid) ? "control" : "interrupt"));
if (l2cap_cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
diff --git a/system/stack/include/avdt_api.h b/system/stack/include/avdt_api.h
index 88ad0661d0..b20f75c4f2 100644
--- a/system/stack/include/avdt_api.h
+++ b/system/stack/include/avdt_api.h
@@ -25,7 +25,6 @@
#ifndef AVDT_API_H
#define AVDT_API_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -69,7 +68,7 @@ inline std::string avdt_result_text(const tAVDT_RESULT& result) {
CASE_RETURN_TEXT(AVDT_BUSY);
CASE_RETURN_TEXT(AVDT_WRITE_FAIL);
default:
- return base::StringPrintf("UNKNOWN[%hu]", result);
+ return std::format("UNKNOWN[{}]", static_cast<uint16_t>(result));
}
}
diff --git a/system/stack/include/btm_api_types.h b/system/stack/include/btm_api_types.h
index 2c2ccf211d..59fde54dad 100644
--- a/system/stack/include/btm_api_types.h
+++ b/system/stack/include/btm_api_types.h
@@ -19,8 +19,6 @@
#ifndef BTM_API_TYPES_H
#define BTM_API_TYPES_H
-#include <base/strings/stringprintf.h>
-
#include <cstdint>
#include <string>
diff --git a/system/stack/include/btm_sec_api_types.h b/system/stack/include/btm_sec_api_types.h
index d04974f259..3721ef302e 100644
--- a/system/stack/include/btm_sec_api_types.h
+++ b/system/stack/include/btm_sec_api_types.h
@@ -18,7 +18,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -64,7 +63,7 @@ inline std::string security_mode_text(const tSECURITY_MODE& security_mode) {
case BTM_SEC_MODE_SC:
return std::string("secure connections only");
default:
- return base::StringPrintf("UNKNOWN[%hhu]", security_mode);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(security_mode));
}
}
@@ -137,7 +136,7 @@ inline std::string linkkey_type_text(const int linkkey_type) {
case BTM_LKEY_TYPE_AUTH_COMB_P_256:
return std::string("AUTH_COMB_P_256");
default:
- return base::StringPrintf("UNKNOWN[0x%02x]", linkkey_type);
+ return std::format("UNKNOWN[0x{:02x}]", linkkey_type);
}
}
@@ -196,7 +195,7 @@ inline std::string sp_evt_to_text(const tBTM_SP_EVT evt) {
CASE_RETURN_TEXT(BTM_SP_RMT_OOB_EVT);
}
- return base::StringPrintf("UNKNOWN[%hhu]", evt);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(evt));
}
enum : uint8_t {
@@ -223,7 +222,7 @@ inline std::string io_capabilities_text(const tBTM_IO_CAP& io_caps) {
case BTM_IO_CAP_KBDISP:
return std::string("Keyboard-Display");
default:
- return base::StringPrintf("UNKNOWN[%hhu]", io_caps);
+ return std::format("UNKNOWN[{}]", io_caps);
}
}
@@ -442,7 +441,7 @@ inline std::string ble_evt_to_text(const tBTM_LE_EVT evt) {
CASE_RETURN_TEXT(BTM_LE_ADDR_ASSOC_EVT);
}
- return base::StringPrintf("UNKNOWN[%hhu]", evt);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(evt));
}
enum : uint8_t {
@@ -521,7 +520,7 @@ inline std::string bond_type_text(const tBTM_BOND_TYPE& bond_type) {
CASE_RETURN_TEXT(BOND_TYPE_PERSISTENT);
CASE_RETURN_TEXT(BOND_TYPE_TEMPORARY);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", bond_type);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(bond_type));
}
}
diff --git a/system/stack/include/btm_status.h b/system/stack/include/btm_status.h
index a33a4b6a87..b3b6be698c 100644
--- a/system/stack/include/btm_status.h
+++ b/system/stack/include/btm_status.h
@@ -16,8 +16,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
-
#include <cstdint>
#include "macros.h"
@@ -94,7 +92,7 @@ inline std::string btm_status_text(const tBTM_STATUS& status) {
CASE_RETURN_TEXT(tBTM_STATUS::BTM_NOT_ENCRYPTED);
CASE_RETURN_TEXT(tBTM_STATUS::BTM_INSUFFICIENT_ENCRYPT_KEY_SIZE);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(status));
}
}
diff --git a/system/stack/include/gap_api.h b/system/stack/include/gap_api.h
index e4a185eefe..f216b12f3b 100644
--- a/system/stack/include/gap_api.h
+++ b/system/stack/include/gap_api.h
@@ -226,6 +226,43 @@ uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle);
/*******************************************************************************
*
+ * Function GAP_GetLeChannelInfo
+ *
+ * Description This function is called to get LE L2CAP channel information
+ * by the gap handle. All OUT parameters must NOT be nullptr.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * remote_mtu - OUT remote L2CAP MTU
+ * local_mps - OUT local L2CAP COC MPS
+ * remote_mps - OUT remote L2CAP COC MPS
+ * local_credit - OUT local L2CAP COC credit
+ * remote_credit - OUT remote L2CAP COC credit
+ * local_cid - OUT local L2CAP CID
+ * remote_cid - OUT remote L2CAP CID
+ * acl_handle - OUT ACL handle
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_GetLeChannelInfo(uint16_t gap_handle, uint16_t* remote_mtu, uint16_t* local_mps,
+ uint16_t* remote_mps, uint16_t* local_credit, uint16_t* remote_credit,
+ uint16_t* local_cid, uint16_t* remote_cid, uint16_t* acl_handle);
+
+/*******************************************************************************
+ *
+ * Function GAP_IsTransportLe
+ *
+ * Description This function returns if the transport is LE by the gap handle.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ *
+ * Returns true if transport is LE, else false
+ *
+ ******************************************************************************/
+bool GAP_IsTransportLe(uint16_t gap_handle);
+
+/*******************************************************************************
+ *
* Function GAP_Init
*
* Description Initializes the control blocks used by GAP.
diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h
index 3b751e10cf..3073a6e145 100644
--- a/system/stack/include/gatt_api.h
+++ b/system/stack/include/gatt_api.h
@@ -18,7 +18,6 @@
#ifndef GATT_API_H
#define GATT_API_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -137,7 +136,7 @@ inline std::string gatt_status_text(const tGATT_STATUS& status) {
CASE_RETURN_TEXT(GATT_PRC_IN_PROGRESS);
CASE_RETURN_TEXT(GATT_OUT_OF_RANGE);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(status));
}
}
@@ -293,7 +292,7 @@ inline std::string gatt_disconnection_reason_text(const tGATT_DISCONN_REASON& re
CASE_RETURN_TEXT(BTA_GATT_CONN_NONE);
CASE_RETURN_TEXT(GATT_CONN_TERMINATED_POWER_OFF);
default:
- return base::StringPrintf("UNKNOWN[%hu]", reason);
+ return std::format("UNKNOWN[{}]", static_cast<uint16_t>(reason));
}
}
diff --git a/system/stack/include/hci_error_code.h b/system/stack/include/hci_error_code.h
index 3d4b50c745..2d70e00010 100644
--- a/system/stack/include/hci_error_code.h
+++ b/system/stack/include/hci_error_code.h
@@ -16,7 +16,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <hardware/bluetooth.h>
@@ -121,7 +120,7 @@ inline std::string hci_error_code_text(const tHCI_ERROR_CODE& error_code) {
CASE_RETURN_TEXT(HCI_ERR_LIMIT_REACHED);
CASE_RETURN_TEXT(HCI_ERR_CANCELLED_BY_LOCAL_HOST);
default:
- return base::StringPrintf("UNKNOWN[0x%02hx]", error_code);
+ return std::format("UNKNOWN[0x{:02x}]", static_cast<uint8_t>(error_code));
}
}
diff --git a/system/stack/include/hiddefs.h b/system/stack/include/hiddefs.h
index 583c302d1f..47bd6f9561 100644
--- a/system/stack/include/hiddefs.h
+++ b/system/stack/include/hiddefs.h
@@ -25,7 +25,6 @@
#ifndef HIDDEFS_H
#define HIDDEFS_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include "internal_include/bt_target.h"
@@ -80,7 +79,7 @@ inline std::string hid_status_text(const tHID_STATUS& status) {
CASE_RETURN_TEXT(HID_ERR_GATT);
CASE_RETURN_TEXT(HID_ERR_INVALID);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(status));
}
}
diff --git a/system/stack/include/l2cap_interface.h b/system/stack/include/l2cap_interface.h
index cfd88153f7..b1551d2a80 100644
--- a/system/stack/include/l2cap_interface.h
+++ b/system/stack/include/l2cap_interface.h
@@ -638,6 +638,7 @@ public:
******************************************************************************/
virtual void L2CA_Consolidate(const RawAddress& identity_addr, const RawAddress& rpa) = 0;
virtual tHCI_ROLE L2CA_GetBleConnRole(const RawAddress& bd_addr) = 0;
+ virtual uint16_t L2CA_GetBleConnInterval(const RawAddress& bd_addr) = 0;
/*******************************************************************************
**
@@ -916,6 +917,40 @@ public:
**
*******************************************************************************/
virtual bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id, bool is_local_cid) = 0;
+
+ /*******************************************************************************
+ **
+ ** Function L2CA_GetAclHandle
+ **
+ ** Description Given a local channel identifier, |lcid|, this function
+ ** returns the handle of the corresponding ACL connection, |acl_handle|. If
+ ** |lcid| is not known or is invalid, this function returns false and does not
+ ** modify the value pointed at by |acl_handle|.
+ **
+ ** Parameters: lcid: Local CID
+ ** acl_handle: Pointer to ACL handle must NOT be nullptr
+ **
+ ** Returns true if acl_handle lookup was successful
+ **
+ ******************************************************************************/
+ virtual bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) = 0;
+
+ /*******************************************************************************
+ **
+ ** Function L2CA_GetLocalMtu
+ **
+ ** Description Given a local channel identifier, |lcid|, this function
+ ** returns the L2CAP local mtu, |local_mtu|. If
+ ** |lcid| is not known or is invalid, this function returns false and does not
+ ** modify the value pointed at by |local_mtu|.
+ **
+ ** Parameters: lcid: Local CID
+ ** local_mtu: Pointer to L2CAP local mtu must NOT be nullptr
+ **
+ ** Returns true if local_mtu lookup was successful
+ **
+ ******************************************************************************/
+ virtual bool L2CA_GetLocalMtu(uint16_t lcid, uint16_t* local_mtu) = 0;
};
Interface& get_interface();
diff --git a/system/stack/include/l2cap_types.h b/system/stack/include/l2cap_types.h
index 311dab7528..d2dd74bad7 100644
--- a/system/stack/include/l2cap_types.h
+++ b/system/stack/include/l2cap_types.h
@@ -129,6 +129,8 @@ typedef struct {
uint8_t fcs; /* '0' if desire is to bypass FCS, otherwise '1' */
bool ext_flow_spec_present;
tHCI_EXT_FLOW_SPEC ext_flow_spec;
+ bool init_credit_present;
+ uint16_t init_credit;
uint16_t flags; /* bit 0: 0-no continuation, 1-continuation */
} tL2CAP_CFG_INFO;
diff --git a/system/stack/include/l2cdefs.h b/system/stack/include/l2cdefs.h
index 88ed7a76d3..be101711da 100644
--- a/system/stack/include/l2cdefs.h
+++ b/system/stack/include/l2cdefs.h
@@ -487,6 +487,7 @@ inline std::string l2cap_cfg_result_text(const tL2CAP_CFG_RESULT& result) {
*/
#define L2CAP_SDU_LENGTH_MAX (8080 + 26 - (L2CAP_MIN_OFFSET + 6))
constexpr uint16_t L2CAP_SDU_LENGTH_LE_MAX = 0xffff;
+constexpr uint16_t L2CAP_SDU_LENGTH_LE_MIN = 23;
/* SAR bits in the control word
*/
diff --git a/system/stack/include/pan_api.h b/system/stack/include/pan_api.h
index 9246f2aa39..a4e10279cf 100644
--- a/system/stack/include/pan_api.h
+++ b/system/stack/include/pan_api.h
@@ -24,7 +24,6 @@
#ifndef PAN_API_H
#define PAN_API_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -58,9 +57,9 @@
typedef uint8_t tPAN_ROLE;
inline const std::string pan_role_to_text(const tPAN_ROLE& role) {
- return base::StringPrintf("%c%c%c[0x%x]", (role & PAN_ROLE_CLIENT) ? 'C' : '.',
- (role & PAN_ROLE_GROUP) ? 'G' : '.',
- (role & PAN_ROLE_NAP_SERVER) ? 'N' : '.', role);
+ return std::format("{:c}{:c}{:c}[0x{:x}]", (role & PAN_ROLE_CLIENT) ? 'C' : '.',
+ (role & PAN_ROLE_GROUP) ? 'G' : '.', (role & PAN_ROLE_NAP_SERVER) ? 'N' : '.',
+ role);
}
/*****************************************************************************
@@ -116,7 +115,7 @@ inline const std::string pan_result_text(const tPAN_RESULT& result) {
CASE_RETURN_TEXT(PAN_FAILURE);
CASE_RETURN_TEXT(PAN_HOTSPOT_DISABLED);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", result);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(result));
}
}
diff --git a/system/stack/include/port_api.h b/system/stack/include/port_api.h
index e2986740f1..3a9fd7e4b3 100644
--- a/system/stack/include/port_api.h
+++ b/system/stack/include/port_api.h
@@ -179,6 +179,17 @@ inline std::string port_result_text(const tPORT_RESULT& result) {
RETURN_UNKNOWN_TYPE_STRING(tPORT_RESULT, result);
}
+/* Define a structure to hold the configuration parameters. Since the
+ * parameters are optional, for each parameter there is a boolean to
+ * use to signify its presence or absence.
+ */
+struct RfcommCfgInfo {
+ bool init_credit_present;
+ uint16_t init_credit;
+ bool rx_mtu_present;
+ uint16_t rx_mtu;
+};
+
namespace std {
template <>
struct formatter<tPORT_RESULT> : enum_formatter<tPORT_RESULT> {};
@@ -192,9 +203,9 @@ typedef void(tPORT_MGMT_CALLBACK)(const tPORT_RESULT code, uint16_t port_handle)
/*******************************************************************************
*
- * Function RFCOMM_CreateConnection
+ * Function RFCOMM_CreateConnectionWithSecurity
*
- * Description RFCOMM_CreateConnection is used from the application to
+ * Description RFCOMM_CreateConnectionWithSecurity is used from the application to
* establish a serial port connection to the peer device,
* or allow RFCOMM to accept a connection from the peer
* application.
@@ -210,6 +221,9 @@ typedef void(tPORT_MGMT_CALLBACK)(const tPORT_RESULT code, uint16_t port_handle)
* p_handle - OUT pointer to the handle.
* p_mgmt_callback - pointer to callback function to receive
* connection up/down events.
+ * sec_mask - bitmask of BTM_SEC_* values indicating the
+ * minimum security requirements for this
+ * cfg - optional configurations for the connection
* Notes:
*
* Server can call this function with the same scn parameter multiple times if
@@ -225,7 +239,7 @@ typedef void(tPORT_MGMT_CALLBACK)(const tPORT_RESULT code, uint16_t port_handle)
uint16_t mtu, const RawAddress& bd_addr,
uint16_t* p_handle,
tPORT_MGMT_CALLBACK* p_mgmt_callback,
- uint16_t sec_mask);
+ uint16_t sec_mask, RfcommCfgInfo cfg);
/*******************************************************************************
*
@@ -483,4 +497,30 @@ void RFCOMM_Init(void);
******************************************************************************/
[[nodiscard]] int PORT_GetSecurityMask(uint16_t handle, uint16_t* sec_mask);
+/*******************************************************************************
+ *
+ * Function PORT_GetChannelInfo
+ *
+ * Description This function is called to get RFCOMM channel information
+ * by the handle of the port. All OUT parameters must NOT be nullptr.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * local_mtu - OUT local L2CAP MTU
+ * remote_mtu - OUT remote L2CAP MTU
+ * local_credit - OUT local RFCOMM credit
+ * remote_credit - OUT remote RFCOMM credit
+ * local_cid - OUT local L2CAP CID
+ * remote_cid - OUT remote L2CAP CID
+ * dlci - OUT dlci
+ * max_frame_size- OUT max frame size for RFCOMM
+ * acl_handle - OUT ACL handle
+ * mux_initiator - OUT is initiator of the RFCOMM multiplexer control channel
+ *
+ ******************************************************************************/
+[[nodiscard]] int PORT_GetChannelInfo(uint16_t handle, uint16_t* local_mtu, uint16_t* remote_mtu,
+ uint16_t* local_credit, uint16_t* remote_credit,
+ uint16_t* local_cid, uint16_t* remote_cid, uint16_t* dlci,
+ uint16_t* max_frame_size, uint16_t* acl_handle,
+ bool* mux_initiator);
+
#endif /* PORT_API_H */
diff --git a/system/stack/include/rfcdefs.h b/system/stack/include/rfcdefs.h
index 628fc77c45..35be4076d6 100644
--- a/system/stack/include/rfcdefs.h
+++ b/system/stack/include/rfcdefs.h
@@ -45,6 +45,11 @@
#define RFCOMM_DEFAULT_MTU 127
/*
+ * The minimum allowed MTU should be 23 according to the RFCOMM specs
+ */
+#define RFCOMM_MIN_MTU 23
+
+/*
* RFCOMM buffer sizes
*/
#define RFCOMM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE // command packet buffer size
diff --git a/system/stack/include/sdp_api.h b/system/stack/include/sdp_api.h
index f639b107f7..a23ba0502d 100644
--- a/system/stack/include/sdp_api.h
+++ b/system/stack/include/sdp_api.h
@@ -19,7 +19,6 @@
#pragma once
#include <base/functional/callback_forward.h>
-#include <base/strings/stringprintf.h>
#include <cstdint>
diff --git a/system/stack/include/sdp_status.h b/system/stack/include/sdp_status.h
index cebcd9697c..363b9c09bd 100644
--- a/system/stack/include/sdp_status.h
+++ b/system/stack/include/sdp_status.h
@@ -18,7 +18,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -82,7 +81,7 @@ inline std::string sdp_status_text(const tSDP_STATUS& status) {
CASE_RETURN_TEXT(tSDP_STATUS::SDP_DB_FULL);
CASE_RETURN_TEXT(tSDP_STATUS::SDP_CANCEL);
default:
- return base::StringPrintf("UNKNOWN[%hu]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint16_t>(status));
}
}
const auto sdp_result_text = sdp_status_text;
diff --git a/system/stack/include/sdpdefs.h b/system/stack/include/sdpdefs.h
index 600bd44fb4..f4f4dba79e 100644
--- a/system/stack/include/sdpdefs.h
+++ b/system/stack/include/sdpdefs.h
@@ -25,8 +25,7 @@
#ifndef SDP_DEFS_H
#define SDP_DEFS_H
-#include <base/strings/stringprintf.h>
-
+#include <format>
#include <string>
#include "macros.h"
@@ -122,7 +121,7 @@ inline std::string sdp_attr_id_text(const unsigned& id) {
CASE_RETURN_TEXT(ATTR_ID_SERVICE_DESCRIPTION);
CASE_RETURN_TEXT(ATTR_ID_PROVIDER_NAME);
default:
- return base::StringPrintf("SDP_ATTR_ID:[%u]", id);
+ return std::format("SDP_ATTR_ID:[{}]", id);
}
}
@@ -152,7 +151,7 @@ inline std::string sdp_attr_type_text(const unsigned& type) {
CASE_RETURN_TEXT(DATA_ELE_ALT_DESC_TYPE);
CASE_RETURN_TEXT(URL_DESC_TYPE);
default:
- return base::StringPrintf("UNKNOWN[%u]", type);
+ return std::format("UNKNOWN[{}]", type);
}
}
@@ -180,7 +179,7 @@ inline std::string sdp_attr_size_text(const unsigned& size) {
CASE_RETURN_TEXT(SIZE_IN_NEXT_WORD);
CASE_RETURN_TEXT(SIZE_IN_NEXT_LONG);
default:
- return base::StringPrintf("UNKNOWN[%u]", size);
+ return std::format("UNKNOWN[{}]", size);
}
}
diff --git a/system/stack/include/smp_api.h b/system/stack/include/smp_api.h
index 6957c71875..291eca99d1 100644
--- a/system/stack/include/smp_api.h
+++ b/system/stack/include/smp_api.h
@@ -200,6 +200,15 @@ void SMP_ClearLocScOobData();
******************************************************************************/
void SMP_SirkConfirmDeviceReply(const RawAddress& bd_addr, uint8_t res);
+/*******************************************************************************
+ *
+ * Function SMP_SirkConfirmDeviceReply
+ *
+ * Description Returns the key size of peinding LE pairing
+ *
+ ******************************************************************************/
+uint16_t SMP_GetPendingPairingKeySize();
+
// Called when LTK request is received from controller.
bool smp_proc_ltk_request(const RawAddress& bda);
diff --git a/system/stack/include/smp_api_types.h b/system/stack/include/smp_api_types.h
index 2a27416acd..db575f0804 100644
--- a/system/stack/include/smp_api_types.h
+++ b/system/stack/include/smp_api_types.h
@@ -19,7 +19,6 @@
#ifndef SMP_API_TYPES_H
#define SMP_API_TYPES_H
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
diff --git a/system/stack/include/smp_status.h b/system/stack/include/smp_status.h
index 5c8b6f16f4..86670a5161 100644
--- a/system/stack/include/smp_status.h
+++ b/system/stack/include/smp_status.h
@@ -18,7 +18,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -91,7 +90,7 @@ inline std::string smp_status_text(const tSMP_STATUS& status) {
CASE_RETURN_TEXT(SMP_SIRK_DEVICE_INVALID);
CASE_RETURN_TEXT(SMP_USER_CANCELLED);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", status);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(status));
}
}
diff --git a/system/stack/include/stack_metrics_logging.h b/system/stack/include/stack_metrics_logging.h
index 912d5a5a91..dda02a0d1d 100644
--- a/system/stack/include/stack_metrics_logging.h
+++ b/system/stack/include/stack_metrics_logging.h
@@ -21,6 +21,8 @@
#include <cstdint>
+#include "hci/address.h"
+#include "hci/hci_packets.h"
#include "types/raw_address.h"
void log_classic_pairing_event(const RawAddress& address, uint16_t handle, uint32_t hci_cmd,
@@ -55,3 +57,10 @@ void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, int num_reque
int codec_type);
void log_le_pairing_fail(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing);
+
+void log_le_connection_status(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason);
+
+void log_le_device_in_accept_list(bluetooth::hci::Address address, bool is_add);
+
+void log_le_connection_lifecycle(bluetooth::hci::Address address, bool is_connect, bool is_direct);
diff --git a/system/stack/l2cap/internal/l2c_api.h b/system/stack/l2cap/internal/l2c_api.h
index 5ed3403cff..dd1dbf52e6 100644
--- a/system/stack/l2cap/internal/l2c_api.h
+++ b/system/stack/l2cap/internal/l2c_api.h
@@ -705,6 +705,7 @@ void L2CA_LockBleConnParamsForProfileConnection(const RawAddress& rem_bda, bool
******************************************************************************/
void L2CA_Consolidate(const RawAddress& identity_addr, const RawAddress& rpa);
[[nodiscard]] tHCI_ROLE L2CA_GetBleConnRole(const RawAddress& bd_addr);
+[[nodiscard]] uint16_t L2CA_GetBleConnInterval(const RawAddress& bd_addr);
void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, uint16_t* max_interval,
uint16_t floor_interval);
@@ -777,3 +778,37 @@ void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status);
**
*******************************************************************************/
[[nodiscard]] bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id, bool is_local_cid);
+
+/*******************************************************************************
+**
+** Function L2CA_GetAclHandle
+**
+** Description Given a local channel identifier, |lcid|, this function
+** returns the handle of the corresponding ACL connection, |acl_handle|. If
+** |lcid| is not known or is invalid, this function returns false and does not
+** modify the value pointed at by |acl_handle|.
+**
+** Parameters: lcid: Local CID
+** acl_handle: Pointer to ACL handle must NOT be nullptr
+**
+** Returns true if acl_handle lookup was successful
+**
+******************************************************************************/
+[[nodiscard]] bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle);
+
+/*******************************************************************************
+ **
+ ** Function L2CA_GetLocalMtu
+ **
+ ** Description Given a local channel identifier, |lcid|, this function
+ ** returns the L2CAP local mtu, |local_mtu|. If
+ ** |lcid| is not known or is invalid, this function returns false and does not
+ ** modify the value pointed at by |local_mtu|.
+ **
+ ** Parameters: lcid: Local CID
+ ** local_mtu: Pointer to L2CAP local mtu must NOT be nullptr
+ **
+ ** Returns true if local_mtu lookup was successful
+ **
+ ******************************************************************************/
+[[nodiscard]] bool L2CA_GetLocalMtu(uint16_t lcid, uint16_t* local_mtu);
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 2b67132edb..d8d2eb0023 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -27,7 +27,6 @@
#include "stack/l2cap/l2c_api.h"
#include <base/location.h>
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -1731,6 +1730,65 @@ bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id, bool is_local_cid
return ret;
}
+/*******************************************************************************
+ *
+ * Function L2CA_GetAclHandle
+ *
+ * Description Given a local channel identifier, |lcid|, this function
+ * returns the bound ACL handle, |acl_handle|. If |acl_handle|
+ * is not known or is invalid, this function returns false and
+ * does not modify the value pointed at by |acl_handle|.
+ *
+ * Parameters: lcid: Local CID
+ * rcid: Pointer to ACL handle must NOT be nullptr
+ *
+ * Return value: true if acl_handle lookup was successful
+ *
+ ******************************************************************************/
+bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) {
+ log::assert_that(acl_handle != nullptr, "assert failed: acl_handle != nullptr");
+
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(nullptr, lcid);
+ if (p_ccb == nullptr) {
+ log::error("No CCB for CID:0x{:04x}", lcid);
+ return false;
+ }
+ uint16_t handle = p_ccb->p_lcb->Handle();
+ if (handle == HCI_INVALID_HANDLE) {
+ log::error("Invalid ACL handle");
+ return false;
+ }
+ *acl_handle = handle;
+ return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function L2CA_GetLocalMtu
+ **
+ ** Description Given a local channel identifier, |lcid|, this function
+ ** returns the L2CAP local mtu, |local_mtu|. If
+ ** |lcid| is not known or is invalid, this function returns false and does not
+ ** modify the value pointed at by |local_mtu|.
+ **
+ ** Parameters: lcid: Local CID
+ ** local_mtu: Pointer to L2CAP local mtu must NOT be nullptr
+ **
+ ** Returns true if local_mtu lookup was successful
+ **
+ ******************************************************************************/
+bool L2CA_GetLocalMtu(uint16_t lcid, uint16_t* local_mtu) {
+ log::assert_that(local_mtu != nullptr, "assert failed: local_mtu != nullptr");
+
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(nullptr, lcid);
+ if (p_ccb == nullptr) {
+ log::error("No CCB for CID:0x{:04x}", lcid);
+ return false;
+ }
+ *local_mtu = p_ccb->p_rcb->my_mtu;
+ return true;
+}
+
using namespace bluetooth;
#define DUMPSYS_TAG "shim::legacy::l2cap"
diff --git a/system/stack/l2cap/l2c_api.h b/system/stack/l2cap/l2c_api.h
index f645803dad..1ff09ffaf5 100644
--- a/system/stack/l2cap/l2c_api.h
+++ b/system/stack/l2cap/l2c_api.h
@@ -106,6 +106,7 @@ public:
void L2CA_LockBleConnParamsForServiceDiscovery(const RawAddress& bd_addr, bool lock) override;
void L2CA_LockBleConnParamsForProfileConnection(const RawAddress& bd_addr, bool lock) override;
[[nodiscard]] tHCI_ROLE L2CA_GetBleConnRole(const RawAddress& bd_addr) override;
+ [[nodiscard]] uint16_t L2CA_GetBleConnInterval(const RawAddress& bd_addr) override;
[[nodiscard]] bool L2CA_SetLeGattTimeout(const RawAddress& bd_addr, uint16_t idle_tout) override;
[[nodiscard]] bool L2CA_MarkLeLinkAsActive(const RawAddress& bd_addr) override;
[[nodiscard]] bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) override;
@@ -133,6 +134,10 @@ public:
void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status) override;
[[nodiscard]] bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id,
bool is_local_cid) override;
+
+ [[nodiscard]] bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) override;
+
+ [[nodiscard]] bool L2CA_GetLocalMtu(uint16_t lcid, uint16_t* local_mtu) override;
};
} // namespace l2cap
diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc
index 9d69e5ab36..2983c5c071 100644
--- a/system/stack/l2cap/l2c_ble.cc
+++ b/system/stack/l2cap/l2c_ble.cc
@@ -24,7 +24,6 @@
#define LOG_TAG "l2c_ble"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -34,6 +33,7 @@
#include "btif/include/core_callbacks.h"
#include "btif/include/stack_manager_t.h"
+#include "common/le_conn_params.h"
#include "hci/controller_interface.h"
#include "hci/hci_interface.h"
#include "internal_include/bt_target.h"
@@ -89,6 +89,15 @@ hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) {
return p_lcb->LinkRole();
}
+uint16_t L2CA_GetBleConnInterval(const RawAddress& bd_addr) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ if (p_lcb == nullptr) {
+ log::error("lcb for {} is not available", bd_addr);
+ return 0;
+ }
+ return p_lcb->ConnInterval();
+}
+
/*******************************************************************************
*
* Function l2cble_notify_le_connection
@@ -108,10 +117,10 @@ void l2cble_notify_le_connection(const RawAddress& bda) {
if (get_btm_client_interface().peer.BTM_IsAclConnectionUp(bda, BT_TRANSPORT_LE) &&
p_lcb->link_state != LST_CONNECTED) {
/* update link status */
+ p_lcb->link_state = LST_CONNECTED;
// TODO Move this back into acl layer
btm_establish_continue_from_address(bda, BT_TRANSPORT_LE);
- /* update l2cap link status and send callback */
- p_lcb->link_state = LST_CONNECTED;
+ /* send callback */
l2cu_process_fixed_chnl_resp(p_lcb);
}
@@ -174,9 +183,26 @@ bool l2cble_conn_comp(uint16_t handle, tHCI_ROLE role, const RawAddress& bda,
/* update link parameter, set peripheral link as non-spec default upon link up
*/
p_lcb->min_interval = p_lcb->max_interval = conn_interval;
+ p_lcb->SetConnInterval(conn_interval);
p_lcb->timeout = conn_timeout;
p_lcb->latency = conn_latency;
p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ uint16_t min_conn_interval_aggressive = LeConnectionParameters::GetMinConnIntervalAggressive();
+ uint16_t max_conn_interval_aggressive = LeConnectionParameters::GetMaxConnIntervalAggressive();
+
+ stack::l2cap::get_interface().L2CA_AdjustConnectionIntervals(
+ &min_conn_interval_aggressive, &max_conn_interval_aggressive, BTM_BLE_CONN_INT_MIN);
+
+ bool is_aggressive_initial_param = conn_interval <= max_conn_interval_aggressive;
+ log::info("conn_interval={}, max_conn_interval_aggressive={}, is_aggressive_initial_param={}",
+ conn_interval, max_conn_interval_aggressive, is_aggressive_initial_param);
+
+ if (is_aggressive_initial_param) {
+ p_lcb->conn_update_mask |= L2C_BLE_AGGRESSIVE_INITIAL_PARAM;
+ }
+ }
+
p_lcb->conn_update_blocked_by_profile_connection = false;
p_lcb->conn_update_blocked_by_service_discovery = false;
@@ -328,6 +354,9 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
p_lcb->latency = latency;
p_lcb->timeout = timeout;
p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM;
+ }
l2cble_start_conn_update(p_lcb);
}
@@ -777,11 +806,21 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
p_ccb->p_rcb = p_rcb;
p_ccb->remote_cid = rcid;
- p_ccb->local_conn_cfg.mtu = L2CAP_SDU_LENGTH_LE_MAX;
- p_ccb->local_conn_cfg.mps =
- bluetooth::shim::GetController()->GetLeBufferSize().le_data_packet_length_;
- p_ccb->local_conn_cfg.credits = L2CA_LeCreditDefault();
- p_ccb->remote_credit_count = L2CA_LeCreditDefault();
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349377
+ p_ccb->local_conn_cfg.mtu = p_rcb->coc_cfg.mtu;
+ p_ccb->local_conn_cfg.mps = p_rcb->coc_cfg.mps;
+ } else {
+ p_ccb->local_conn_cfg.mtu = L2CAP_SDU_LENGTH_LE_MAX;
+ p_ccb->local_conn_cfg.mps =
+ bluetooth::shim::GetController()->GetLeBufferSize().le_data_packet_length_;
+ }
+ if (com::android::bluetooth::flags::socket_settings_api()) { // Added with aosp/3349376
+ p_ccb->local_conn_cfg.credits = p_rcb->coc_cfg.credits;
+ p_ccb->remote_credit_count = p_rcb->coc_cfg.credits;
+ } else {
+ p_ccb->local_conn_cfg.credits = L2CA_LeCreditDefault();
+ p_ccb->remote_credit_count = L2CA_LeCreditDefault();
+ }
p_ccb->peer_conn_cfg.mtu = mtu;
p_ccb->peer_conn_cfg.mps = mps;
@@ -925,7 +964,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
/** This function is to initiate a direct connection. Returns true if connection
* initiated, false otherwise. */
bool l2cble_create_conn(tL2C_LCB* p_lcb) {
- if (!connection_manager::create_le_connection(CONN_MGR_ID_L2CAP, p_lcb->remote_bd_addr)) {
+ if (!connection_manager::direct_connect_add(CONN_MGR_ID_L2CAP, p_lcb->remote_bd_addr)) {
return false;
}
@@ -1149,7 +1188,7 @@ void l2cble_process_data_length_change_event(uint16_t handle, uint16_t tx_data_l
"{}",
p_lcb->remote_bd_addr, p_lcb->tx_data_len, tx_data_len);
BTM_LogHistory(kBtmLogTag, p_lcb->remote_bd_addr, "LE Data length change",
- base::StringPrintf("tx_octets:%hu => %hu", p_lcb->tx_data_len, tx_data_len));
+ std::format("tx_octets:{} => {}", p_lcb->tx_data_len, tx_data_len));
p_lcb->tx_data_len = tx_data_len;
} else {
log::debug(
diff --git a/system/stack/l2cap/l2c_ble_conn_params.cc b/system/stack/l2cap/l2c_ble_conn_params.cc
index 1e9d4ba7ab..47c19f3a3c 100644
--- a/system/stack/l2cap/l2c_ble_conn_params.cc
+++ b/system/stack/l2cap/l2c_ble_conn_params.cc
@@ -26,7 +26,9 @@
#define LOG_TAG "l2c_ble_conn_params"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
+#include "common/le_conn_params.h"
#include "hci/controller_interface.h"
#include "hci/event_checkers.h"
#include "hci/hci_interface.h"
@@ -34,6 +36,7 @@
#include "internal_include/stack_config.h"
#include "main/shim/acl_api.h"
#include "main/shim/entry.h"
+#include "osi/include/properties.h"
#include "stack/btm/btm_dev.h"
#include "stack/include/acl_api.h"
#include "stack/include/btm_ble_api_types.h"
@@ -85,6 +88,10 @@ bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int, uint1
p_lcb->latency = latency;
p_lcb->timeout = timeout;
p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM;
+ }
+
p_lcb->min_ce_len = min_ce_len;
p_lcb->max_ce_len = max_ce_len;
@@ -117,7 +124,15 @@ void L2CA_LockBleConnParamsForServiceDiscovery(const RawAddress& rem_bda, bool l
if (lock == p_lcb->conn_update_blocked_by_service_discovery) {
log::warn("{} service discovery already locked/unlocked conn params: {}", rem_bda, lock);
- return;
+
+ if (!lock && com::android::bluetooth::flags::initial_conn_params_p1() &&
+ (p_lcb->conn_update_mask & L2C_BLE_AGGRESSIVE_INITIAL_PARAM)) {
+ p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM;
+ p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+ log::info("Service discovery is skipped. Relaxing connection parameters.");
+ } else {
+ return;
+ }
}
p_lcb->conn_update_blocked_by_service_discovery = lock;
@@ -217,11 +232,41 @@ void l2cble_start_conn_update(tL2C_LCB* p_lcb) {
/* application requests to disable parameters update.
If parameters are already updated, lets set them
up to what has been requested during connection establishement */
- if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM &&
- /* current connection interval is greater than default min */
- p_lcb->min_interval > BTM_BLE_CONN_INT_MIN) {
- /* use 7.5 ms as fast connection parameter, 0 peripheral latency */
- min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
+ if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM) {
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ min_conn_int = LeConnectionParameters::GetMinConnIntervalAggressive();
+ max_conn_int = LeConnectionParameters::GetMaxConnIntervalAggressive();
+ log::info("min_conn_int={}, max_conn_int={}", min_conn_int, max_conn_int);
+
+ if (p_lcb->conn_update_mask & L2C_BLE_AGGRESSIVE_INITIAL_PARAM) {
+ // Usually, we can use the same aggressive connection parameters for service discovery.
+ // However when hearing aid is being used, the connection intervals may need to be
+ // adjusted.
+ uint16_t adjusted_min_conn_int = min_conn_int;
+ uint16_t adjusted_max_conn_int = max_conn_int;
+
+ stack::l2cap::get_interface().L2CA_AdjustConnectionIntervals(
+ &adjusted_min_conn_int, &adjusted_max_conn_int, BTM_BLE_CONN_INT_MIN);
+
+ log::info("adjusted_min_conn_int={}, adjusted_max_conn_int={}", adjusted_min_conn_int,
+ adjusted_max_conn_int);
+
+ if ((adjusted_min_conn_int == min_conn_int) && (adjusted_max_conn_int == max_conn_int)) {
+ log::info("No need to update connection parameters.");
+ p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM;
+ p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+ return;
+ }
+ }
+ } else {
+ if (p_lcb->min_interval <= BTM_BLE_CONN_INT_MIN) {
+ // Skip updating connection parameters for service discovery if we are already
+ // using default minimum interval.
+ return;
+ }
+ /* use 7.5 ms as fast connection parameter, 0 peripheral latency */
+ min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
+ }
stack::l2cap::get_interface().L2CA_AdjustConnectionIntervals(&min_conn_int, &max_conn_int,
BTM_BLE_CONN_INT_MIN);
@@ -250,6 +295,15 @@ void l2cble_start_conn_update(tL2C_LCB* p_lcb) {
if (p_lcb->IsLinkRoleCentral() ||
(bluetooth::shim::GetController()->SupportsBleConnectionParametersRequest() &&
acl_peer_supports_ble_connection_parameters_request(p_lcb->remote_bd_addr))) {
+ if (com::android::bluetooth::flags::initial_conn_params_p1() &&
+ (p_lcb->conn_update_mask & L2C_BLE_AGGRESSIVE_INITIAL_PARAM)) {
+ log::info("Relaxing aggressive initial connection parameters. addr={}",
+ p_lcb->remote_bd_addr);
+ p_lcb->min_interval = LeConnectionParameters::GetMinConnIntervalRelaxed();
+ p_lcb->max_interval = LeConnectionParameters::GetMaxConnIntervalRelaxed();
+ p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM;
+ }
+
acl_ble_connection_parameters_request(p_lcb->Handle(), p_lcb->min_interval,
p_lcb->max_interval, p_lcb->latency, p_lcb->timeout,
p_lcb->min_ce_len, p_lcb->max_ce_len);
@@ -275,7 +329,7 @@ void l2cble_start_conn_update(tL2C_LCB* p_lcb) {
* Returns void
*
******************************************************************************/
-void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status, uint16_t /* interval */,
+void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status, uint16_t interval,
uint16_t /* latency */, uint16_t /* timeout */) {
log::verbose("");
@@ -285,7 +339,7 @@ void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status, uint16_t /*
log::warn("Invalid handle: {}", handle);
return;
}
-
+ p_lcb->SetConnInterval(interval);
p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING;
if (status != HCI_SUCCESS) {
@@ -321,6 +375,9 @@ void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min, uint
p_lcb->max_interval = int_max;
p_lcb->latency = latency;
p_lcb->timeout = timeout;
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM;
+ }
/* if update is enabled, always accept connection parameter update */
if ((p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) == 0) {
@@ -370,6 +427,9 @@ void l2cble_use_preferred_conn_params(const RawAddress& bda) {
p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int;
p_lcb->timeout = p_dev_rec->conn_params.supervision_tout;
p_lcb->latency = p_dev_rec->conn_params.peripheral_latency;
+ if (com::android::bluetooth::flags::initial_conn_params_p1()) {
+ p_lcb->conn_update_mask &= ~L2C_BLE_AGGRESSIVE_INITIAL_PARAM;
+ }
acl_ble_connection_parameters_request(p_lcb->Handle(), p_dev_rec->conn_params.min_conn_int,
p_dev_rec->conn_params.max_conn_int,
diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h
index 0077cab5bf..639cee872e 100644
--- a/system/stack/l2cap/l2c_int.h
+++ b/system/stack/l2cap/l2c_int.h
@@ -23,7 +23,6 @@
******************************************************************************/
#pragma once
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <stdbool.h>
@@ -95,7 +94,7 @@ inline std::string channel_state_text(const tL2C_CHNL_STATE& state) {
CASE_RETURN_TEXT(CST_W4_L2CAP_DISCONNECT_RSP);
CASE_RETURN_TEXT(CST_W4_L2CA_DISCONNECT_RSP);
default:
- return base::StringPrintf("UNKNOWN[%d]", state);
+ return std::format("UNKNOWN[{}]", static_cast<int>(state));
}
}
@@ -395,6 +394,8 @@ enum tCONN_UPDATE_MASK : uint8_t {
L2C_BLE_UPDATE_PENDING = (1u << 2),
/* not using default connection parameters */
L2C_BLE_NOT_DEFAULT_PARAM = (1u << 3),
+ /* Aggressive initial connection parameters are used */
+ L2C_BLE_AGGRESSIVE_INITIAL_PARAM = (1u << 4),
};
/* Define a link control block. There is one link control block between
@@ -429,6 +430,7 @@ public:
private:
tHCI_ROLE link_role_{HCI_ROLE_CENTRAL}; /* Central or peripheral */
+ uint16_t conn_interval_;
public:
tHCI_ROLE LinkRole() const { return link_role_; }
@@ -436,6 +438,8 @@ public:
bool IsLinkRolePeripheral() const { return link_role_ == HCI_ROLE_PERIPHERAL; }
void SetLinkRoleAsCentral() { link_role_ = HCI_ROLE_CENTRAL; }
void SetLinkRoleAsPeripheral() { link_role_ = HCI_ROLE_PERIPHERAL; }
+ uint16_t ConnInterval() const { return conn_interval_; }
+ void SetConnInterval(uint16_t conn_interval) { conn_interval_ = conn_interval; }
uint8_t signal_id; /* Signalling channel id */
uint8_t cur_echo_id; /* Current id value for echo request */
diff --git a/system/stack/l2cap/l2c_utils.cc b/system/stack/l2cap/l2c_utils.cc
index c04379bf89..c18ba8c5a9 100644
--- a/system/stack/l2cap/l2c_utils.cc
+++ b/system/stack/l2cap/l2c_utils.cc
@@ -3331,6 +3331,9 @@ void l2cu_send_peer_ble_credit_based_conn_res(tL2C_CCB* p_ccb, tL2CAP_LE_RESULT_
p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD +
L2CAP_CMD_OVERHEAD;
+ log::verbose("local cid: {}, mtu: {}, mps: {}, initial credits: {}", p_ccb->local_cid,
+ p_ccb->local_conn_cfg.mtu, p_ccb->local_conn_cfg.mps, p_ccb->local_conn_cfg.credits);
+
UINT16_TO_STREAM(p, p_ccb->local_cid); /* Local CID */
UINT16_TO_STREAM(p, p_ccb->local_conn_cfg.mtu); /* MTU */
UINT16_TO_STREAM(p, p_ccb->local_conn_cfg.mps); /* MPS */
diff --git a/system/stack/l2cap/l2cap_api.cc b/system/stack/l2cap/l2cap_api.cc
index 94466c90e2..0752c995c0 100644
--- a/system/stack/l2cap/l2cap_api.cc
+++ b/system/stack/l2cap/l2cap_api.cc
@@ -214,6 +214,11 @@ void bluetooth::stack::l2cap::Impl::L2CA_Consolidate(const RawAddress& identity_
return ::L2CA_GetBleConnRole(bd_addr);
}
+[[nodiscard]] uint16_t bluetooth::stack::l2cap::Impl::L2CA_GetBleConnInterval(
+ const RawAddress& bd_addr) {
+ return ::L2CA_GetBleConnInterval(bd_addr);
+}
+
void bluetooth::stack::l2cap::Impl::L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
uint16_t* max_interval,
uint16_t floor_interval) {
@@ -257,3 +262,13 @@ void bluetooth::stack::l2cap::Impl::L2CA_SetMediaStreamChannel(uint16_t local_me
uint16_t* rcid) {
return ::L2CA_GetRemoteChannelId(lcid, rcid);
}
+
+[[nodiscard]] bool bluetooth::stack::l2cap::Impl::L2CA_GetAclHandle(uint16_t lcid,
+ uint16_t* acl_handle) {
+ return ::L2CA_GetAclHandle(lcid, acl_handle);
+}
+
+[[nodiscard]] bool bluetooth::stack::l2cap::Impl::L2CA_GetLocalMtu(uint16_t lcid,
+ uint16_t* local_mtu) {
+ return ::L2CA_GetLocalMtu(lcid, local_mtu);
+}
diff --git a/system/stack/metrics/stack_metrics_logging.cc b/system/stack/metrics/stack_metrics_logging.cc
index 4a6326f2ee..ffe7a43488 100644
--- a/system/stack/metrics/stack_metrics_logging.cc
+++ b/system/stack/metrics/stack_metrics_logging.cc
@@ -81,3 +81,16 @@ void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, int num_reque
void log_le_pairing_fail(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing) {
bluetooth::shim::LogMetricLePairingFail(raw_address, failure_reason, is_outgoing);
}
+
+void log_le_connection_status(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason) {
+ bluetooth::shim::LogMetricLeConnectionStatus(address, is_connect, reason);
+}
+
+void log_le_device_in_accept_list(bluetooth::hci::Address address, bool is_add) {
+ bluetooth::shim::LogMetricLeDeviceInAcceptList(address, is_add);
+}
+
+void log_le_connection_lifecycle(bluetooth::hci::Address address, bool is_connect, bool is_direct) {
+ bluetooth::shim::LogMetricLeConnectionLifecycle(address, is_connect, is_direct);
+}
diff --git a/system/stack/mmc/main.cc b/system/stack/mmc/main.cc
index 75de58852e..3f24e7851c 100644
--- a/system/stack/mmc/main.cc
+++ b/system/stack/mmc/main.cc
@@ -19,7 +19,6 @@
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/run_loop.h>
-#include <base/strings/stringprintf.h>
#include <base/task/single_thread_task_executor.h>
#include <bluetooth/log.h>
#include <sys/syslog.h>
@@ -44,8 +43,7 @@ const int kSyslogCritical = LOG_CRIT;
static bool MessageHandler(int severity, const char* file, int line, size_t message_start,
const std::string& message) {
- const auto str =
- base::StringPrintf("%s:%d - %s", file, line, message.substr(message_start).c_str());
+ const auto str = std::format("{}:{} - {}", file, line, message.substr(message_start));
switch (severity) {
case logging::LOGGING_INFO:
diff --git a/system/stack/pan/pan_api.cc b/system/stack/pan/pan_api.cc
index 0d6d17f368..432a071ec7 100644
--- a/system/stack/pan/pan_api.cc
+++ b/system/stack/pan/pan_api.cc
@@ -27,7 +27,6 @@
#include "stack/include/pan_api.h"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <cstdint>
@@ -231,8 +230,7 @@ tPAN_RESULT PAN_SetRole(uint8_t role, std::string p_user_name, std::string p_nap
pan_cb.role = role;
log::verbose("PAN role set to: {}", role);
- BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Role change",
- base::StringPrintf("role:0x%x", role));
+ BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Role change", std::format("role:0x{:x}", role));
return PAN_SUCCESS;
}
@@ -687,7 +685,7 @@ void PAN_Dumpsys(int fd) {
if (pcb->con_state == PAN_STATE_IDLE) {
continue;
}
- LOG_DUMPSYS(fd, " Id:%d peer:%s", i, ADDRESS_TO_LOGGABLE_CSTR(pcb->rem_bda));
+ LOG_DUMPSYS(fd, " Id:%d peer:%s", i, pcb->rem_bda.ToRedactedStringForLogging().c_str());
LOG_DUMPSYS(fd, " rx_packets:%-5lu rx_octets:%-8lu rx_errors:%-5lu rx_drops:%-5lu",
(unsigned long)pcb->read.packets, (unsigned long)pcb->read.octets,
(unsigned long)pcb->read.errors, (unsigned long)pcb->read.drops);
diff --git a/system/stack/pan/pan_main.cc b/system/stack/pan/pan_main.cc
index f4e7a65226..49afce8324 100644
--- a/system/stack/pan/pan_main.cc
+++ b/system/stack/pan/pan_main.cc
@@ -25,7 +25,6 @@
#define LOG_TAG "pan"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <string.h> // memset
diff --git a/system/stack/rfcomm/port_api.cc b/system/stack/rfcomm/port_api.cc
index 6786e88d02..d483a99d07 100644
--- a/system/stack/rfcomm/port_api.cc
+++ b/system/stack/rfcomm/port_api.cc
@@ -26,8 +26,8 @@
#include "stack/include/port_api.h"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <cstdint>
@@ -97,6 +97,7 @@ const char kBtmLogTag[] = "RFCOMM";
* connection up/down events.
* sec_mask - bitmask of BTM_SEC_* values indicating the
* minimum security requirements for this
+ * cfg - optional configurations for the connection
*connection Notes:
*
* Server can call this function with the same scn parameter multiple times if
@@ -110,7 +111,8 @@ const char kBtmLogTag[] = "RFCOMM";
******************************************************************************/
int RFCOMM_CreateConnectionWithSecurity(uint16_t uuid, uint8_t scn, bool is_server, uint16_t mtu,
const RawAddress& bd_addr, uint16_t* p_handle,
- tPORT_MGMT_CALLBACK* p_mgmt_callback, uint16_t sec_mask) {
+ tPORT_MGMT_CALLBACK* p_mgmt_callback, uint16_t sec_mask,
+ RfcommCfgInfo cfg) {
*p_handle = 0;
if ((scn == 0) || (scn > RFCOMM_MAX_SCN)) {
@@ -198,6 +200,16 @@ int RFCOMM_CreateConnectionWithSecurity(uint16_t uuid, uint8_t scn, bool is_serv
p_port->mtu = rfcomm_mtu;
}
+ // Set the optional configuration for future use when the server or client negotiates the
+ // parameters with the peer device.
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ p_port->rfc_cfg_info = cfg;
+ // Update the local mtu with the optional configuration if set by the app
+ if (p_port->rfc_cfg_info.rx_mtu_present) {
+ p_port->mtu = p_port->rfc_cfg_info.rx_mtu;
+ }
+ }
+
// Other states
// server doesn't need to release port when closing
if (is_server) {
@@ -219,15 +231,13 @@ int RFCOMM_CreateConnectionWithSecurity(uint16_t uuid, uint8_t scn, bool is_serv
// If this is not initiator of the connection need to just wait
if (p_port->is_server) {
- BTM_LogHistory(
- kBtmLogTag, bd_addr, "Server started",
- base::StringPrintf("handle:%hu scn:%hhu dlci:%hhu mtu:%hu", *p_handle, scn, dlci, mtu));
+ BTM_LogHistory(kBtmLogTag, bd_addr, "Server started",
+ std::format("handle:{} scn:{} dlci:{} mtu:{}", *p_handle, scn, dlci, mtu));
return PORT_SUCCESS;
}
- BTM_LogHistory(
- kBtmLogTag, bd_addr, "Connection opened",
- base::StringPrintf("handle:%hu scn:%hhu dlci:%hhu mtu:%hu", *p_handle, scn, dlci, mtu));
+ BTM_LogHistory(kBtmLogTag, bd_addr, "Connection opened",
+ std::format("handle:{} scn:{} dlci:{} mtu:{}", *p_handle, scn, dlci, mtu));
// Open will be continued after security checks are passed
return port_open_continue(p_port);
@@ -306,10 +316,9 @@ int RFCOMM_RemoveConnection(uint16_t handle) {
const RawAddress bd_addr =
(p_port->rfc.p_mcb) ? (p_port->rfc.p_mcb->bd_addr) : (RawAddress::kEmpty);
- BTM_LogHistory(
- kBtmLogTag, bd_addr, "Connection closed",
- base::StringPrintf("handle:%hu scn:%hhu dlci:%hhu is_server:%s", handle, p_port->scn,
- p_port->dlci, p_port->is_server ? "true" : "false"));
+ BTM_LogHistory(kBtmLogTag, bd_addr, "Connection closed",
+ std::format("handle:{} scn:{} dlci:{} is_server:{}", handle, p_port->scn,
+ p_port->dlci, p_port->is_server));
p_port->state = PORT_CONNECTION_STATE_CLOSING;
@@ -345,10 +354,9 @@ int RFCOMM_RemoveServer(uint16_t handle) {
const RawAddress bd_addr =
(p_port->rfc.p_mcb) ? (p_port->rfc.p_mcb->bd_addr) : (RawAddress::kEmpty);
- BTM_LogHistory(
- kBtmLogTag, bd_addr, "Server stopped",
- base::StringPrintf("handle:%hu scn:%hhu dlci:%hhu is_server:%s", handle, p_port->scn,
- p_port->dlci, p_port->is_server ? "true" : "false"));
+ BTM_LogHistory(kBtmLogTag, bd_addr, "Server stopped",
+ std::format("handle:{} scn:{} dlci:{} is_server:{}", handle, p_port->scn,
+ p_port->dlci, p_port->is_server));
/* this port will be deallocated after closing */
p_port->keep_port_handle = false;
@@ -1194,3 +1202,51 @@ int PORT_GetSecurityMask(uint16_t handle, uint16_t* sec_mask) {
*sec_mask = p_port->sec_mask;
return PORT_SUCCESS;
}
+
+int PORT_GetChannelInfo(uint16_t handle, uint16_t* local_mtu, uint16_t* remote_mtu,
+ uint16_t* local_credit, uint16_t* remote_credit, uint16_t* local_cid,
+ uint16_t* remote_cid, uint16_t* dlci, uint16_t* max_frame_size,
+ uint16_t* acl_handle, bool* mux_initiator) {
+ log::verbose("PORT_GetChannelInfo() handle:{}", handle);
+
+ tPORT* p_port = get_port_from_handle(handle);
+ if (p_port == nullptr) {
+ log::error("Unable to get RFCOMM port control block bad handle:{}", handle);
+ return PORT_BAD_HANDLE;
+ }
+
+ if (!p_port->in_use || (p_port->state == PORT_CONNECTION_STATE_CLOSED)) {
+ return PORT_NOT_OPENED;
+ }
+
+ if (p_port->line_status) {
+ return PORT_LINE_ERR;
+ }
+
+ uint16_t rcid, ahandle, lmtu;
+ if (!stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_port->rfc.p_mcb->lcid, &rcid)) {
+ log::error("L2CA_GetRemoteChannelId failed, local cid: {}", p_port->rfc.p_mcb->lcid);
+ return PORT_PEER_FAILED;
+ }
+
+ if (!stack::l2cap::get_interface().L2CA_GetAclHandle(p_port->rfc.p_mcb->lcid, &ahandle)) {
+ log::error("L2CA_GetAclHandle failed, local cid: {}", p_port->rfc.p_mcb->lcid);
+ return PORT_PEER_FAILED;
+ }
+
+ if (!stack::l2cap::get_interface().L2CA_GetLocalMtu(p_port->rfc.p_mcb->lcid, &lmtu)) {
+ log::error("L2CA_GetLocalMtu failed, local cid: {}", p_port->rfc.p_mcb->lcid);
+ return PORT_PEER_FAILED;
+ }
+ *local_mtu = lmtu;
+ *remote_mtu = p_port->rfc.p_mcb->peer_l2cap_mtu + RFCOMM_MIN_OFFSET + 1;
+ *local_credit = p_port->credit_rx;
+ *remote_credit = p_port->credit_tx;
+ *local_cid = p_port->rfc.p_mcb->lcid;
+ *remote_cid = rcid;
+ *dlci = p_port->dlci;
+ *max_frame_size = p_port->mtu;
+ *acl_handle = ahandle;
+ *mux_initiator = p_port->rfc.p_mcb->is_initiator;
+ return PORT_SUCCESS;
+}
diff --git a/system/stack/rfcomm/port_int.h b/system/stack/rfcomm/port_int.h
index 8fcbf845fd..94d9f4cc8b 100644
--- a/system/stack/rfcomm/port_int.h
+++ b/system/stack/rfcomm/port_int.h
@@ -205,6 +205,8 @@ typedef struct {
uint16_t keep_mtu; /* Max MTU that port can receive by server */
uint16_t sec_mask; /* Bitmask of security requirements for this port */
/* see the BTM_SEC_* values in btm_api_types.h */
+ RfcommCfgInfo rfc_cfg_info; /* store optional rfc configure info for incoming */
+ /* connection while connecting */
} tPORT;
/* Define the PORT/RFCOMM control structure
diff --git a/system/stack/rfcomm/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc
index 1f8ba0b5ad..01c8270869 100644
--- a/system/stack/rfcomm/port_rfc.cc
+++ b/system/stack/rfcomm/port_rfc.cc
@@ -27,6 +27,7 @@
#include <base/functional/callback.h>
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
#include <cstdint>
@@ -344,7 +345,13 @@ void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uin
/* Set convergence layer and number of credits (k) */
our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R;
- our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ our_k = (p_port->rfc_cfg_info.init_credit_present) ? p_port->rfc_cfg_info.init_credit
+ : (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
+ : RFCOMM_K_MAX;
+ } else {
+ our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+ }
p_port->credit_rx = our_k;
} else {
/* must not be using credit based flow control; use TS 7.10 */
diff --git a/system/stack/rfcomm/rfc_mx_fsm.cc b/system/stack/rfcomm/rfc_mx_fsm.cc
index c9890023d5..c2a00bdfa5 100644
--- a/system/stack/rfcomm/rfc_mx_fsm.cc
+++ b/system/stack/rfcomm/rfc_mx_fsm.cc
@@ -346,7 +346,7 @@ void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* /* p_da
case RFC_MX_EVENT_DM:
rfc_timer_stop(p_mcb);
- FALLTHROUGH_INTENDED; /* FALLTHROUGH */
+ [[fallthrough]];
case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
diff --git a/system/stack/rfcomm/rfc_port_if.cc b/system/stack/rfcomm/rfc_port_if.cc
index c6c37cc11c..0973f0370a 100644
--- a/system/stack/rfcomm/rfc_port_if.cc
+++ b/system/stack/rfcomm/rfc_port_if.cc
@@ -26,6 +26,7 @@
#define LOG_TAG "rfcomm"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <cstdint>
#include <unordered_map>
@@ -149,7 +150,14 @@ void RFCOMM_ParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t
/* Set convergence layer and number of credits (k) */
if (flow == PORT_FC_CREDIT) {
cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
- k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+
+ if (com::android::bluetooth::flags::socket_settings_api()) {
+ k = (p_port->rfc_cfg_info.init_credit_present) ? p_port->rfc_cfg_info.init_credit
+ : (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
+ : RFCOMM_K_MAX;
+ } else {
+ k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+ }
p_port->credit_rx = k;
} else {
cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
diff --git a/system/stack/rfcomm/rfc_ts_frames.cc b/system/stack/rfcomm/rfc_ts_frames.cc
index e9df718116..495d0aea08 100644
--- a/system/stack/rfcomm/rfc_ts_frames.cc
+++ b/system/stack/rfcomm/rfc_ts_frames.cc
@@ -35,9 +35,6 @@
#include "stack/rfcomm/port_int.h"
#include "stack/rfcomm/rfc_int.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
/*******************************************************************************
@@ -378,7 +375,7 @@ void rfc_send_rls(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command, uint8_t status
* Description This function sends Non Supported Command Response.
*
******************************************************************************/
-void rfc_send_nsc(tRFC_MCB* p_mcb) {
+static void rfc_send_nsc(tRFC_MCB* p_mcb) {
uint8_t* p_data;
BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
diff --git a/system/stack/rnr/remote_name_request.cc b/system/stack/rnr/remote_name_request.cc
index ed6801a855..bd0fcbce44 100644
--- a/system/stack/rnr/remote_name_request.cc
+++ b/system/stack/rnr/remote_name_request.cc
@@ -27,16 +27,12 @@
#include "stack/btm/security_device_record.h"
#include "stack/include/btm_client_interface.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+using namespace bluetooth;
extern tBTM_CB btm_cb;
-using namespace bluetooth;
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_read_remote_name_cmpl(bool status, const RawAddress& bda, uint16_t length,
- char* p_name);
bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
int i;
@@ -80,7 +76,7 @@ bool BTM_IsRemoteNameKnown(const RawAddress& bd_addr, tBT_TRANSPORT /* transport
* Returns void
*
******************************************************************************/
-void btm_inq_rmt_name_failed_cancelled(void) {
+static void btm_inq_rmt_name_failed_cancelled(void) {
log::error("remname_active={}", btm_cb.rnr.remname_active);
if (btm_cb.rnr.remname_active) {
@@ -123,8 +119,8 @@ static uint16_t get_clock_offset_from_storage(const RawAddress& remote_bda) {
: 0;
}
-tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda, uint64_t timeout_ms,
- tBTM_NAME_CMPL_CB* p_cb) {
+static tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda, uint64_t timeout_ms,
+ tBTM_NAME_CMPL_CB* p_cb) {
/*** Make sure the device is ready ***/
if (!get_btm_client_interface().local.BTM_IsDeviceUp()) {
return tBTM_STATUS::BTM_WRONG_MODE;
diff --git a/system/stack/rnr/remote_name_request.h b/system/stack/rnr/remote_name_request.h
index 6df83680dc..356f24ca49 100644
--- a/system/stack/rnr/remote_name_request.h
+++ b/system/stack/rnr/remote_name_request.h
@@ -151,6 +151,8 @@ tBTM_STATUS BTM_CancelRemoteDeviceName(void);
void btm_process_remote_name(const RawAddress* bda, const BD_NAME bdn, uint16_t /* evt_len */,
tHCI_STATUS hci_status);
+void btm_inq_remote_name_timer_timeout(void* data);
+
namespace bluetooth {
namespace stack {
namespace rnr {
diff --git a/system/stack/sdp/sdp_api.cc b/system/stack/sdp/sdp_api.cc
index 093dddde82..2380b76043 100644
--- a/system/stack/sdp/sdp_api.cc
+++ b/system/stack/sdp/sdp_api.cc
@@ -26,7 +26,6 @@
#include "stack/include/sdp_api.h"
-#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
#include <string.h>
diff --git a/system/stack/sdp/sdp_discovery.cc b/system/stack/sdp/sdp_discovery.cc
index 183c3e7193..d3284892c8 100644
--- a/system/stack/sdp/sdp_discovery.cc
+++ b/system/stack/sdp/sdp_discovery.cc
@@ -25,6 +25,7 @@
#define LOG_TAG "stack::sdp"
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <cstdint>
@@ -636,6 +637,16 @@ static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
uint8_t* p;
uint16_t bytes_left = SDP_DATA_BUF_SIZE;
+ /* If we don't have a valid discovery database, we can't do anything. */
+ if (com::android::bluetooth::flags::btsec_check_valid_discovery_database() &&
+ p_ccb->p_db == NULL) {
+ log::warn(
+ "Attempted continuation or first time request with invalid discovery "
+ "database");
+ sdp_disconnect(p_ccb, tSDP_STATUS::SDP_INVALID_CONT_STATE);
+ return;
+ }
+
p_msg->offset = L2CAP_MIN_OFFSET;
p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
diff --git a/system/stack/sdp/sdpint.h b/system/stack/sdp/sdpint.h
index e831065798..07d2a1e12a 100644
--- a/system/stack/sdp/sdpint.h
+++ b/system/stack/sdp/sdpint.h
@@ -25,7 +25,6 @@
#pragma once
#include <base/functional/callback.h>
-#include <base/strings/stringprintf.h>
#include <cstdint>
#include <string>
@@ -220,7 +219,7 @@ inline std::string sdp_disc_wait_text(const tSDP_DISC_WAIT& state) {
CASE_RETURN_TEXT(SDP_DISC_WAIT_SEARCH_ATTR);
CASE_RETURN_TEXT(SDP_DISC_WAIT_CANCEL);
default:
- return base::StringPrintf("UNKNOWN[%d]", state);
+ return std::format("UNKNOWN[{}]", state);
}
}
diff --git a/system/stack/smp/smp_act.cc b/system/stack/smp/smp_act.cc
index 777bb012a6..c625217c7c 100644
--- a/system/stack/smp/smp_act.cc
+++ b/system/stack/smp/smp_act.cc
@@ -269,7 +269,7 @@ void smp_send_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC && p_cb->status != SMP_SUCCESS) {
log::error("Pairing failed smp_status:{}", smp_status_text(p_cb->status));
BTM_LogHistory(kBtmLogTag, p_cb->pairing_bda, "Pairing failed",
- base::StringPrintf("smp_status:%s", smp_status_text(p_cb->status).c_str()));
+ std::format("smp_status:{}", smp_status_text(p_cb->status)));
smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
p_cb->wait_for_authorization_complete = true;
}
@@ -1220,8 +1220,8 @@ void smp_sirk_verify(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
smp_int_data.status = SMP_SIRK_DEVICE_INVALID;
BTM_LogHistory(kBtmLogTag, p_cb->pairing_bda, "SIRK verification",
- base::StringPrintf("Verification failed, smp_status:%s",
- smp_status_text(smp_int_data.status).c_str()));
+ std::format("Verification failed, smp_status:{}",
+ smp_status_text(smp_int_data.status)));
smp_sm_event(p_cb, SMP_SIRK_DEVICE_VALID_EVT, &smp_int_data);
@@ -1235,7 +1235,7 @@ void smp_sirk_verify(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
/* There is no member validator callback - device is by default valid */
if (callback_rc == tBTM_STATUS::BTM_SUCCESS_NO_SECURITY) {
BTM_LogHistory(kBtmLogTag, p_cb->pairing_bda, "SIRK verification",
- base::StringPrintf("Device validated due to no security"));
+ std::format("Device validated due to no security"));
tSMP_INT_DATA smp_int_data;
smp_int_data.status = SMP_SUCCESS;
diff --git a/system/stack/smp/smp_api.cc b/system/stack/smp/smp_api.cc
index 4485bf3fcb..0d66b0a064 100644
--- a/system/stack/smp/smp_api.cc
+++ b/system/stack/smp/smp_api.cc
@@ -525,3 +525,8 @@ void SMP_SirkConfirmDeviceReply(const RawAddress& bd_addr, uint8_t res) {
smp_sm_event(p_cb, SMP_SIRK_DEVICE_VALID_EVT, &smp_int_data);
}
}
+
+uint16_t SMP_GetPendingPairingKeySize() {
+ tSMP_CB* p_cb = &smp_cb;
+ return p_cb->loc_enc_size;
+} \ No newline at end of file
diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h
index 7725bd7e6d..438fe1e8eb 100644
--- a/system/stack/smp/smp_int.h
+++ b/system/stack/smp/smp_int.h
@@ -105,7 +105,7 @@ inline std::string smp_opcode_text(const tSMP_OPCODE opcode) {
CASE_RETURN_TEXT(SMP_OPCODE_PAIR_KEYPR_NOTIF);
CASE_RETURN_TEXT(SMP_OPCODE_PAIR_COMMITM);
default:
- return base::StringPrintf("UNKNOWN[%hhu]", opcode);
+ return std::format("UNKNOWN[{}]", static_cast<uint8_t>(opcode));
}
}
diff --git a/system/stack/smp/smp_main.cc b/system/stack/smp/smp_main.cc
index 26635cf4d8..cfc8df3725 100644
--- a/system/stack/smp/smp_main.cc
+++ b/system/stack/smp/smp_main.cc
@@ -916,9 +916,9 @@ void smp_set_state(tSMP_STATE state) {
log::debug("State change: {}({})==>{}({})", smp_get_state_name(smp_cb.state), smp_cb.state,
smp_get_state_name(state), state);
if (smp_cb.state != state) {
- BTM_LogHistory(kBtmLogTag, smp_cb.pairing_ble_bd_addr, "Security state changed",
- base::StringPrintf("%s => %s", smp_get_state_name(smp_cb.state),
- smp_get_state_name(state)));
+ BTM_LogHistory(
+ kBtmLogTag, smp_cb.pairing_ble_bd_addr, "Security state changed",
+ std::format("{} => {}", smp_get_state_name(smp_cb.state), smp_get_state_name(state)));
}
smp_cb.state = state;
} else {
diff --git a/system/stack/smp/smp_utils.cc b/system/stack/smp/smp_utils.cc
index 2c4f43746b..81b005a78c 100644
--- a/system/stack/smp/smp_utils.cc
+++ b/system/stack/smp/smp_utils.cc
@@ -997,7 +997,7 @@ void smp_proc_pairing_cmpl(tSMP_CB* p_cb) {
"sec_level:0x{:0x}",
p_cb->pairing_bda, smp_status_text(evt_data.cmplt.reason), evt_data.cmplt.sec_level);
BTM_LogHistory(kBtmLogTag, pairing_bda, "Pairing failed",
- base::StringPrintf("reason:%s", smp_status_text(evt_data.cmplt.reason).c_str()));
+ std::format("reason:{}", smp_status_text(evt_data.cmplt.reason)));
}
// Log pairing complete event
diff --git a/system/stack/srvc/srvc_dis.cc b/system/stack/srvc/srvc_dis.cc
index 38751c653c..2a0014e5c1 100644
--- a/system/stack/srvc/srvc_dis.cc
+++ b/system/stack/srvc/srvc_dis.cc
@@ -32,9 +32,6 @@
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
static const uint16_t dis_attr_uuid[] = {
@@ -120,7 +117,7 @@ static void dis_gatt_c_read_dis_value_cmpl(tCONN_ID conn_id) {
* Returns void
*
******************************************************************************/
-bool dis_gatt_c_read_dis_req(tCONN_ID conn_id) {
+static bool dis_gatt_c_read_dis_req(tCONN_ID conn_id) {
tGATT_READ_PARAM param;
memset(&param, 0, sizeof(tGATT_READ_PARAM));
diff --git a/system/stack/test/a2dp/mock_bta_av_codec.cc b/system/stack/test/a2dp/mock_bta_av_codec.cc
index c261bebfe9..6c0a80d0da 100644
--- a/system/stack/test/a2dp/mock_bta_av_codec.cc
+++ b/system/stack/test/a2dp/mock_bta_av_codec.cc
@@ -15,8 +15,6 @@
*/
#include "a2dp_codec_api.h"
-
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#include "btif/include/btif_av_co.h"
A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) { return nullptr; }
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 e86e7eaced..7f5e27f26f 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
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <base/strings/stringprintf.h>
#include <gtest/gtest.h>
#include <stdlib.h>
@@ -118,7 +117,7 @@ protected:
void setup_thread() {
for (size_t i = 0; i < kNumberOfThreads; i++) {
- std::string name = base::StringPrintf("thread:%zu", i);
+ std::string name = std::format("thread:{}", i);
threads[i] = thread_new(name.c_str());
}
}
diff --git a/system/stack/test/btm/stack_btm_inq_test.cc b/system/stack/test/btm/stack_btm_inq_test.cc
index 160ff6124f..70219a92c2 100644
--- a/system/stack/test/btm/stack_btm_inq_test.cc
+++ b/system/stack/test/btm/stack_btm_inq_test.cc
@@ -36,9 +36,6 @@
#include "test/mock/mock_main_shim_entry.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
extern tBTM_CB btm_cb;
using bluetooth::common::ContextualCallback;
@@ -129,11 +126,12 @@ public:
MockBtmInquiryCallbacks* inquiry_callback_ptr = nullptr;
-void btm_inq_results_cb(tBTM_INQ_RESULTS* p_inq_results, const uint8_t* p_eir, uint16_t eir_len) {
+static void btm_inq_results_cb(tBTM_INQ_RESULTS* p_inq_results, const uint8_t* p_eir,
+ uint16_t eir_len) {
inquiry_callback_ptr->btm_inq_results_cb(p_inq_results, p_eir, eir_len);
}
-void btm_inq_cmpl_cb(void* p1) { inquiry_callback_ptr->btm_inq_cmpl_cb(p1); }
+static void btm_inq_cmpl_cb(void* p1) { inquiry_callback_ptr->btm_inq_cmpl_cb(p1); }
class BtmDeviceInquiryTest : public BtmInqTest {
protected:
diff --git a/system/stack/test/btm/stack_btm_sec_test.cc b/system/stack/test/btm/stack_btm_sec_test.cc
index daa6bfbfb4..3bfac8572d 100644
--- a/system/stack/test/btm/stack_btm_sec_test.cc
+++ b/system/stack/test/btm/stack_btm_sec_test.cc
@@ -226,7 +226,7 @@ TEST_F(StackBtmSecTest, btm_oob_data_text) {
for (const auto& data : datas) {
ASSERT_STREQ(data.second.c_str(), btm_oob_data_text(data.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[%hhu]", std::numeric_limits<std::uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<std::uint8_t>::max());
ASSERT_STREQ(
unknown.c_str(),
btm_oob_data_text(static_cast<tBTM_OOB_DATA>(std::numeric_limits<std::uint8_t>::max()))
@@ -242,7 +242,7 @@ TEST_F(StackBtmSecTest, bond_type_text) {
for (const auto& data : datas) {
ASSERT_STREQ(data.second.c_str(), bond_type_text(data.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[%hhu]", std::numeric_limits<std::uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<std::uint8_t>::max());
ASSERT_STREQ(unknown.c_str(),
bond_type_text(static_cast<tBTM_BOND_TYPE>(std::numeric_limits<std::uint8_t>::max()))
.c_str());
diff --git a/system/stack/test/btm/stack_btm_test.cc b/system/stack/test/btm/stack_btm_test.cc
index c308911bce..7471d4faca 100644
--- a/system/stack/test/btm/stack_btm_test.cc
+++ b/system/stack/test/btm/stack_btm_test.cc
@@ -32,15 +32,13 @@
#include "stack/include/acl_hci_link_interface.h"
#include "stack/include/btm_client_interface.h"
#include "stack/l2cap/l2c_int.h"
+#include "stack/rnr/remote_name_request.h"
#include "stack/test/btm/btm_test_fixtures.h"
#include "test/common/mock_functions.h"
#include "test/mock/mock_legacy_hci_interface.h"
#include "test/mock/mock_main_shim_entry.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using ::testing::_;
using ::testing::Each;
using ::testing::Eq;
@@ -50,11 +48,11 @@ extern tBTM_CB btm_cb;
tL2C_CB l2cb;
-void btm_inq_remote_name_timer_timeout(void*) {}
-
const std::string kSmpOptions("mock smp options");
const std::string kBroadcastAudioConfigOptions("mock broadcast audio config options");
+void btm_inq_remote_name_timer_timeout(void*) {}
+
namespace {
using testing::Return;
diff --git a/system/stack/test/btm_iso_test.cc b/system/stack/test/btm_iso_test.cc
index 3cb550b04d..40453f703d 100644
--- a/system/stack/test/btm_iso_test.cc
+++ b/system/stack/test/btm_iso_test.cc
@@ -27,14 +27,12 @@
#include "stack/btm/btm_dev.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_types.h"
+#include "stack/include/btm_log_history.h"
#include "stack/include/hci_error_code.h"
#include "stack/include/hcidefs.h"
#include "test/mock/mock_main_shim_entry.h"
#include "test/mock/mock_main_shim_hci_layer.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using bluetooth::hci::IsoManager;
using testing::_;
using testing::AnyNumber;
@@ -448,14 +446,14 @@ protected:
void CleanupIsoManager() override { /* DO NOTHING */ }
};
-bool operator==(const EXT_CIS_CFG& x, const EXT_CIS_CFG& y) {
+static bool operator==(const EXT_CIS_CFG& x, const EXT_CIS_CFG& y) {
return (x.cis_id == y.cis_id) && (x.max_sdu_size_mtos == y.max_sdu_size_mtos) &&
(x.max_sdu_size_stom == y.max_sdu_size_stom) && (x.phy_mtos == y.phy_mtos) &&
(x.phy_stom == y.phy_stom) && (x.rtn_mtos == y.rtn_mtos) && (x.rtn_stom == y.rtn_stom);
}
-bool operator==(const struct bluetooth::hci::iso_manager::cig_create_params& x,
- const struct bluetooth::hci::iso_manager::cig_create_params& y) {
+static bool operator==(const struct bluetooth::hci::iso_manager::cig_create_params& x,
+ const struct bluetooth::hci::iso_manager::cig_create_params& y) {
return (x.sdu_itv_mtos == y.sdu_itv_mtos) && (x.sdu_itv_stom == y.sdu_itv_stom) &&
(x.sca == y.sca) && (x.packing == y.packing) && (x.framing == y.framing) &&
(x.max_trans_lat_stom == y.max_trans_lat_stom) &&
@@ -463,8 +461,8 @@ bool operator==(const struct bluetooth::hci::iso_manager::cig_create_params& x,
std::is_permutation(x.cis_cfgs.begin(), x.cis_cfgs.end(), y.cis_cfgs.begin());
}
-bool operator==(const struct bluetooth::hci::iso_manager::big_create_params& x,
- const struct bluetooth::hci::iso_manager::big_create_params& y) {
+static bool operator==(const struct bluetooth::hci::iso_manager::big_create_params& x,
+ const struct bluetooth::hci::iso_manager::big_create_params& y) {
return (x.adv_handle == y.adv_handle) && (x.num_bis == y.num_bis) && (x.sdu_itv == y.sdu_itv) &&
(x.max_sdu_size == y.max_sdu_size) &&
(x.max_transport_latency == y.max_transport_latency) && (x.rtn == y.rtn) &&
diff --git a/system/stack/test/common/mock_btif_storage.cc b/system/stack/test/common/mock_btif_storage.cc
deleted file mode 100644
index bf51e41c63..0000000000
--- a/system/stack/test/common/mock_btif_storage.cc
+++ /dev/null
@@ -1,33 +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 "mock_btif_storage.h"
-
-#include "stack/include/btm_sec_api_types.h"
-
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
-static bluetooth::manager::MockBtifStorageInterface* btif_storage_interface = nullptr;
-
-void bluetooth::manager::SetMockBtifStorageInterface(
- MockBtifStorageInterface* mock_btif_storage_interface) {
- btif_storage_interface = mock_btif_storage_interface;
-}
-
-void btif_storage_load_bonded_eatt(void) { btif_storage_interface->LoadBondedEatt(); }
diff --git a/system/stack/test/common/mock_btif_storage.h b/system/stack/test/common/mock_btif_storage.h
deleted file mode 100644
index cc7da1cf7d..0000000000
--- a/system/stack/test/common/mock_btif_storage.h
+++ /dev/null
@@ -1,45 +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.
- *
- ******************************************************************************/
-#pragma once
-
-#include <gmock/gmock.h>
-
-namespace bluetooth {
-namespace manager {
-
-class BtifStorageInterface {
-public:
- virtual void LoadBondedEatt(void) = 0;
- virtual ~BtifStorageInterface() = default;
-};
-
-class MockBtifStorageInterface : public BtifStorageInterface {
-public:
- MOCK_METHOD0(LoadBondedEatt, void(void));
-};
-
-/**
- * Set the {@link MockBifStorageInterface} for testing
- *
- * @param mock_btif_storage_interface pointer to mock btm security
- * internal interface, could be null
- */
-void SetMockBtifStorageInterface(MockBtifStorageInterface* mock_btif_storage_interface);
-
-} // namespace manager
-} // namespace bluetooth
diff --git a/system/stack/test/common/mock_btm_api_layer.cc b/system/stack/test/common/mock_btm_api_layer.cc
index 735d6be806..83d969dc72 100644
--- a/system/stack/test/common/mock_btm_api_layer.cc
+++ b/system/stack/test/common/mock_btm_api_layer.cc
@@ -17,8 +17,8 @@
#include "mock_btm_api_layer.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#include "stack/btm/btm_ble_sec.h"
+#include "stack/btm/btm_sec.h"
static bluetooth::manager::MockBtmApiInterface* btm_api_interface = nullptr;
diff --git a/system/stack/test/common/mock_btm_layer.cc b/system/stack/test/common/mock_btm_layer.cc
index 129b58ce18..cde4cab07f 100644
--- a/system/stack/test/common/mock_btm_layer.cc
+++ b/system/stack/test/common/mock_btm_layer.cc
@@ -18,13 +18,11 @@
#include "mock_btm_layer.h"
+#include "stack/include/acl_api.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/rfcdefs.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
static bluetooth::manager::MockBtmSecurityInternalInterface* btm_security_internal_interface =
nullptr;
diff --git a/system/stack/test/common/mock_btu_layer.cc b/system/stack/test/common/mock_btu_layer.cc
deleted file mode 100644
index 26ab4b58c5..0000000000
--- a/system/stack/test/common/mock_btu_layer.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2018 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 "common/message_loop_thread.h"
-
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
-bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
diff --git a/system/stack/test/common/mock_l2cap_layer.cc b/system/stack/test/common/mock_l2cap_layer.cc
index b61b80c567..8383cead45 100644
--- a/system/stack/test/common/mock_l2cap_layer.cc
+++ b/system/stack/test/common/mock_l2cap_layer.cc
@@ -23,9 +23,6 @@
#include "stack/l2cap/l2c_int.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
static bluetooth::l2cap::MockL2capInterface* l2cap_interface = nullptr;
void bluetooth::l2cap::SetMockInterface(MockL2capInterface* mock_l2cap_interface) {
@@ -47,16 +44,6 @@ uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& bd_addr) {
bool L2CA_DisconnectReq(uint16_t cid) { return l2cap_interface->DisconnectRequest(cid); }
-bool L2CA_DisconnectRsp(uint16_t cid) { return l2cap_interface->DisconnectResponse(cid); }
-
-bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
- return l2cap_interface->ConfigRequest(cid, p_cfg);
-}
-
-bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
- return l2cap_interface->ConfigResponse(cid, p_cfg);
-}
-
tL2CAP_DW_RESULT L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
return l2cap_interface->DataWrite(cid, p_data);
}
@@ -72,6 +59,10 @@ tHCI_ROLE L2CA_GetBleConnRole(const RawAddress& bd_addr) {
return to_hci_role(l2cap_interface->GetBleConnRole(bd_addr));
}
+uint16_t L2CA_GetBleConnInterval(const RawAddress& bd_addr) {
+ return l2cap_interface->GetBleConnInterval(bd_addr);
+}
+
std::vector<uint16_t> L2CA_ConnectCreditBasedReq(uint16_t psm, const RawAddress& bd_addr,
tL2CAP_LE_CFG_INFO* p_cfg) {
return l2cap_interface->ConnectCreditBasedReq(psm, bd_addr, p_cfg);
diff --git a/system/stack/test/common/mock_l2cap_layer.h b/system/stack/test/common/mock_l2cap_layer.h
index 6c4f3ed4e7..1b069fce14 100644
--- a/system/stack/test/common/mock_l2cap_layer.h
+++ b/system/stack/test/common/mock_l2cap_layer.h
@@ -71,6 +71,7 @@ public:
uint16_t(uint16_t psm, const tL2CAP_APPL_INFO& cb_info, uint16_t sec_level));
MOCK_METHOD1(DeregisterLECoc, void(uint16_t psm));
MOCK_METHOD1(GetBleConnRole, uint8_t(const RawAddress& bd_addr));
+ MOCK_METHOD1(GetBleConnInterval, uint16_t(const RawAddress& bd_addr));
MOCK_METHOD5(ConnectCreditBasedRsp,
bool(const RawAddress& p_bd_addr, uint8_t id, std::vector<uint16_t>& lcids,
tL2CAP_LE_RESULT_CODE result, tL2CAP_LE_CFG_INFO* p_cfg));
diff --git a/system/stack/test/common/mock_stack_avdt_msg.cc b/system/stack/test/common/mock_stack_avdt_msg.cc
index 22a5afce90..7accae9435 100644
--- a/system/stack/test/common/mock_stack_avdt_msg.cc
+++ b/system/stack/test/common/mock_stack_avdt_msg.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "mock_stack_avdt_msg.h"
+
#include <vector>
#include "stack/avdt/avdt_int.h"
@@ -25,9 +27,6 @@
* Need to consider more sophisticated existing methods.
*/
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
static std::vector<uint8_t> _rsp_sig_ids{};
void avdt_msg_send_rsp(AvdtpCcb* /*p_ccb*/, uint8_t sig_id, tAVDT_MSG* /*p_params*/) {
diff --git a/system/stack/test/connection_manager_test.cc b/system/stack/test/connection_manager_test.cc
index cbb7b3ff35..8c99963279 100644
--- a/system/stack/test/connection_manager_test.cc
+++ b/system/stack/test/connection_manager_test.cc
@@ -9,13 +9,19 @@
#include <memory>
+#include "gd/hci/controller_interface_mock.h"
+#include "main/shim/acl_api.h"
+#include "main/shim/entry.h"
+#include "main/shim/le_scanning_manager.h"
#include "osi/include/alarm.h"
#include "osi/test/alarm_mock.h"
#include "security_device_record.h"
+#include "stack/btm/btm_dev.h"
+#include "stack/btm/internal/btm_api.h"
#include "stack/btm/neighbor_inquiry.h"
-
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#include "stack/include/btm_ble_api.h"
+#include "stack/include/btm_log_history.h"
+#include "stack/l2cap/internal/l2c_api.h"
using testing::_;
using testing::DoAll;
@@ -69,6 +75,13 @@ void ACL_IgnoreLeConnectionFrom(const tBLE_BD_ADDR& address) {
void ACL_IgnoreAllLeConnections() { return localAcceptlistMock->AcceptlistClear(); }
+testing::NiceMock<bluetooth::hci::testing::MockControllerInterface> controller;
+
+hci::ControllerInterface* GetController() {
+ ON_CALL(controller, GetLeFilterAcceptListSize).WillByDefault(Return(128));
+ return &controller;
+}
+
} // namespace shim
} // namespace bluetooth
@@ -86,7 +99,7 @@ void set_target_announcements_filter(bool /*enable*/) {}
} // namespace bluetooth
bool L2CA_ConnectFixedChnl(uint16_t /*fixed_cid*/, const RawAddress& /*bd_addr*/) { return false; }
-uint16_t BTM_GetHCIConnHandle(RawAddress const&, unsigned char) { return 0xFFFF; }
+uint16_t BTM_GetHCIConnHandle(RawAddress const&, tBT_TRANSPORT) { return 0xFFFF; }
namespace connection_manager {
class BleConnectionManager : public testing::Test {
@@ -258,9 +271,10 @@ TEST_F(BleConnectionManager, test_app_unregister) {
*/
EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1, true)).WillOnce(Return(true));
- EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address2, false)).WillOnce(Return(true));
EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
+ EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address2, false)).WillOnce(Return(true));
EXPECT_TRUE(background_connect_add(CLIENT1, address2));
+ EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address2, true)).WillOnce(Return(true));
EXPECT_TRUE(direct_connect_add(CLIENT2, address2));
Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
@@ -270,6 +284,8 @@ TEST_F(BleConnectionManager, test_app_unregister) {
EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address2)).Times(1);
on_app_deregistered(CLIENT2);
+
+ Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
}
/** Verify adding device to both direct connection and background connection. */
diff --git a/system/stack/test/eatt/eatt_test.cc b/system/stack/test/eatt/eatt_test.cc
index 437a2f13ef..31ceba5060 100644
--- a/system/stack/test/eatt/eatt_test.cc
+++ b/system/stack/test/eatt/eatt_test.cc
@@ -27,7 +27,6 @@
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_psm_types.h"
#include "stack/include/l2cdefs.h"
-#include "stack/test/common/mock_btif_storage.h"
#include "stack/test/common/mock_btm_api_layer.h"
#include "stack/test/common/mock_eatt.h"
#include "stack/test/common/mock_gatt_layer.h"
@@ -36,9 +35,6 @@
#include "test/mock/mock_stack_l2cap_interface.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using testing::_;
using testing::DoAll;
using testing::MockFunction;
@@ -59,7 +55,6 @@ extern struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_;
/* Needed for testing context */
static tGATT_TCB test_tcb;
-void btif_storage_add_eatt_supported(const RawAddress& /*addr*/) { return; }
void gatt_consolidate(const RawAddress& /*identity_addr*/, const RawAddress& /*rpa*/) {}
void gatt_data_process(tGATT_TCB& /*tcb*/, uint16_t /*cid*/, BT_HDR* /*p_buf*/) { return; }
tGATT_TCB* gatt_find_tcb_by_addr(const RawAddress& /*bda*/, tBT_TRANSPORT /*transport*/) {
@@ -227,7 +222,6 @@ protected:
EXPECT_CALL(controller_, GetLeBufferSize).WillRepeatedly(Return(le_buffer_size_));
bluetooth::l2cap::SetMockInterface(&l2cap_interface_);
bluetooth::manager::SetMockBtmApiInterface(&btm_api_interface_);
- bluetooth::manager::SetMockBtifStorageInterface(&btif_storage_interface_);
bluetooth::gatt::SetMockGattInterface(&gatt_interface_);
bluetooth::hci::testing::mock_controller_ = &controller_;
@@ -237,8 +231,6 @@ protected:
EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_RegisterLECoc(BT_PSM_EATT, _, _, _))
.WillOnce(DoAll(SaveArg<1>(&l2cap_app_info_), ::testing::ReturnArg<0>()));
- ON_CALL(btif_storage_interface_, LoadBondedEatt).WillByDefault([]() { return; });
-
hci_role_ = HCI_ROLE_CENTRAL;
EXPECT_CALL(l2cap_interface_, LeCreditDefault()).WillRepeatedly(DoAll(Return(0xfff)));
@@ -265,7 +257,6 @@ protected:
bluetooth::gatt::SetMockGattInterface(nullptr);
bluetooth::l2cap::SetMockInterface(nullptr);
bluetooth::testing::stack::l2cap::reset_interface();
- bluetooth::manager::SetMockBtifStorageInterface(nullptr);
bluetooth::manager::SetMockBtmApiInterface(nullptr);
bluetooth::hci::testing::mock_controller_ = nullptr;
@@ -274,7 +265,6 @@ protected:
tL2CAP_APPL_INFO reg_info_;
- bluetooth::manager::MockBtifStorageInterface btif_storage_interface_;
bluetooth::manager::MockBtmApiInterface btm_api_interface_;
bluetooth::l2cap::MockL2capInterface l2cap_interface_;
bluetooth::testing::stack::l2cap::Mock mock_stack_l2cap_interface_;
diff --git a/system/stack/test/fuzzers/Android.bp b/system/stack/test/fuzzers/Android.bp
index af2ad8623c..30ad5a5092 100644
--- a/system/stack/test/fuzzers/Android.bp
+++ b/system/stack/test/fuzzers/Android.bp
@@ -38,7 +38,6 @@ cc_defaults {
"android.system.suspend.control-V1-ndk",
"bluetooth_flags_c_lib",
"libFraunhoferAAC",
- "libbluetooth-dumpsys",
"libbluetooth-types",
"libbluetooth_core_rs",
"libbluetooth_crypto_toolbox",
diff --git a/system/stack/test/gatt/mock_gatt_utils_ref.cc b/system/stack/test/gatt/mock_gatt_utils_ref.cc
index fcd758640f..a7b9082824 100644
--- a/system/stack/test/gatt/mock_gatt_utils_ref.cc
+++ b/system/stack/test/gatt/mock_gatt_utils_ref.cc
@@ -14,52 +14,45 @@
* limitations under the License.
*/
+#include "stack/connection_manager/connection_manager.h"
#include "stack/gatt/gatt_int.h"
#include "stack/include/bt_hdr.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-
-/** stack/connection_manager/connection_manager.cc */
-namespace connection_manager {
-bool background_connect_remove(uint8_t app_id, const RawAddress& address) { return false; }
-bool direct_connect_remove(uint8_t app_id, const RawAddress& address, bool connection_timeout) {
- return false;
-}
-bool is_background_connection(const RawAddress& address) { return false; }
-} // namespace connection_manager
-
/** stack/gatt/att_protocol.cc */
-BT_HDR* attp_build_sr_msg(tGATT_TCB& tcb, uint8_t op_code, tGATT_SR_MSG* p_msg,
- uint16_t payload_size) {
+BT_HDR* attp_build_sr_msg(tGATT_TCB& /*tcb*/, uint8_t /*op_code*/, tGATT_SR_MSG* /*p_msg*/,
+ uint16_t /*payload_size*/) {
return nullptr;
}
-tGATT_STATUS attp_send_cl_confirmation_msg(tGATT_TCB& tcb, uint16_t cid) { return GATT_SUCCESS; }
-tGATT_STATUS attp_send_cl_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint8_t op_code,
- tGATT_CL_MSG* p_msg) {
+tGATT_STATUS attp_send_cl_confirmation_msg(tGATT_TCB& /*tcb*/, uint16_t /*cid*/) {
+ return GATT_SUCCESS;
+}
+tGATT_STATUS attp_send_cl_msg(tGATT_TCB& /*tcb*/, tGATT_CLCB* /*p_clcb*/, uint8_t /*op_code*/,
+ tGATT_CL_MSG* /*p_msg*/) {
+ return GATT_SUCCESS;
+}
+tGATT_STATUS attp_send_sr_msg(tGATT_TCB& /*tcb*/, uint16_t /*cid*/, BT_HDR* /*p_msg*/) {
return GATT_SUCCESS;
}
-tGATT_STATUS attp_send_sr_msg(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_msg) { return GATT_SUCCESS; }
/** stack/gatt/gatt_attr.cc */
-void gatt_sr_init_cl_status(tGATT_TCB& tcb) {}
+void gatt_sr_init_cl_status(tGATT_TCB& /*tcb*/) {}
/** stack/gatt/gatt_cl.cc */
-void gatt_act_discovery(tGATT_CLCB* p_clcb) {}
+void gatt_act_discovery(tGATT_CLCB* /*p_clcb*/) {}
/** stack/gatt/gatt_main.cc */
-void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb, bool is_add,
- bool check_acl_link) {}
+void gatt_update_app_use_link_flag(tGATT_IF /*gatt_if*/, tGATT_TCB* /*p_tcb*/, bool /*is_add*/,
+ bool /*check_acl_link*/) {}
void gatts_proc_srv_chg_ind_ack(tGATT_TCB) {}
-bool gatt_disconnect(tGATT_TCB* p_tcb) { return false; }
-void gatt_cancel_connect(const RawAddress& bd_addr, tBT_TRANSPORT transport) {}
-tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) { return GATT_CH_CLOSE; }
-void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) {}
+bool gatt_disconnect(tGATT_TCB* /*p_tcb*/) { return false; }
+void gatt_cancel_connect(const RawAddress& /*bd_addr*/, tBT_TRANSPORT /*transport*/) {}
+tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* /*p_tcb*/) { return GATT_CH_CLOSE; }
+void gatt_set_ch_state(tGATT_TCB* /*p_tcb*/, tGATT_CH_STATE /*ch_state*/) {}
/** stack/gatt/gatt_sr.cc */
-uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint16_t cid, uint8_t op_code, uint16_t handle) {
+uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& /*tcb*/, uint16_t /*cid*/, uint8_t /*op_code*/,
+ uint16_t /*handle*/) {
return 0x0000;
}
-void gatt_dequeue_sr_cmd(tGATT_TCB& tcb, uint16_t cid) {}
+void gatt_dequeue_sr_cmd(tGATT_TCB& /*tcb*/, uint16_t /*cid*/) {}
diff --git a/system/stack/test/gatt/stack_gatt_test.cc b/system/stack/test/gatt/stack_gatt_test.cc
index 96f248af2e..71928440a4 100644
--- a/system/stack/test/gatt/stack_gatt_test.cc
+++ b/system/stack/test/gatt/stack_gatt_test.cc
@@ -217,7 +217,7 @@ TEST_F(StackGattTest, gatt_status_text) {
ASSERT_STREQ(status.second.c_str(), gatt_status_text(status.first).c_str());
}
// Typical max value is already classified so use arbitrary unused one.
- auto unknown = base::StringPrintf("UNKNOWN[%hhu]", 0xfc);
+ auto unknown = std::format("UNKNOWN[{}]", 0xfc);
ASSERT_STREQ(unknown.c_str(), gatt_status_text(static_cast<tGATT_STATUS>(0xfc)).c_str());
}
diff --git a/system/stack/test/hci/stack_hci_test.cc b/system/stack/test/hci/stack_hci_test.cc
index 93d1de3f16..c489f40d95 100644
--- a/system/stack/test/hci/stack_hci_test.cc
+++ b/system/stack/test/hci/stack_hci_test.cc
@@ -172,7 +172,7 @@ TEST_F(StackHciTest, hci_error_code_text) {
for (const auto& error : errors) {
ASSERT_STREQ(error.second.c_str(), hci_error_code_text(error.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[0x%02hx]", std::numeric_limits<std::uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[0x{:02x}]", std::numeric_limits<std::uint8_t>::max());
ASSERT_STREQ(unknown.c_str(),
hci_error_code_text(
static_cast<tHCI_ERROR_CODE>(std::numeric_limits<std::uint8_t>::max()))
diff --git a/system/stack/test/hid/stack_hid_test.cc b/system/stack/test/hid/stack_hid_test.cc
index 7fc527ac2b..641d75101e 100644
--- a/system/stack/test/hid/stack_hid_test.cc
+++ b/system/stack/test/hid/stack_hid_test.cc
@@ -19,13 +19,12 @@
#include "common/message_loop_thread.h"
#include "stack/hid/hidh_int.h"
+#include "stack/include/acl_api.h"
#include "stack/include/hci_error_code.h"
+#include "stack/include/main_thread.h"
#include "test/common/mock_functions.h"
#include "test/mock/mock_stack_l2cap_interface.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
tHCI_REASON btm_get_acl_disc_reason_code(void) { return HCI_SUCCESS; }
diff --git a/system/stack/test/rfcomm/stack_rfcomm_test.cc b/system/stack/test/rfcomm/stack_rfcomm_test.cc
index c15bd8fb55..a39597c0b2 100644
--- a/system/stack/test/rfcomm/stack_rfcomm_test.cc
+++ b/system/stack/test/rfcomm/stack_rfcomm_test.cc
@@ -34,12 +34,9 @@
#include "stack/test/rfcomm/stack_rfcomm_test_utils.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
-std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
+static std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
std::stringstream str;
str.setf(std::ios_base::hex, std::ios::basefield);
str.setf(std::ios_base::uppercase);
@@ -51,14 +48,14 @@ std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
return str.str();
}
-std::string DumpBtHdrToString(BT_HDR* p_hdr) {
+static std::string DumpBtHdrToString(BT_HDR* p_hdr) {
uint8_t* p_hdr_data = p_hdr->data + p_hdr->offset;
return DumpByteBufferToString(p_hdr_data, p_hdr->len);
}
-void PrintTo(BT_HDR* value, ::std::ostream* os) { *os << DumpBtHdrToString(value); }
+static void PrintTo(BT_HDR* value, ::std::ostream* os) { *os << DumpBtHdrToString(value); }
-void PrintTo(tL2CAP_CFG_INFO* value, ::std::ostream* os) {
+static void PrintTo(tL2CAP_CFG_INFO* value, ::std::ostream* os) {
*os << DumpByteBufferToString((uint8_t*)value, sizeof(tL2CAP_CFG_INFO));
}
@@ -136,7 +133,8 @@ public:
uint16_t* server_handle) {
log::verbose("Step 1");
ASSERT_EQ(RFCOMM_CreateConnectionWithSecurity(uuid, scn, true, mtu, RawAddress::kAny,
- server_handle, management_callback, 0),
+ server_handle, management_callback, 0,
+ RfcommCfgInfo{}),
PORT_SUCCESS);
ASSERT_EQ(PORT_SetEventMaskAndCallback(*server_handle, PORT_EV_RXCHAR, event_callback),
PORT_SUCCESS);
@@ -261,9 +259,10 @@ public:
EXPECT_CALL(l2cap_interface_, DataWrite(lcid, BtHdrEqual(uih_pn_channel_3)))
.WillOnce(Return(tL2CAP_DW_RESULT::SUCCESS));
}
- ASSERT_EQ(RFCOMM_CreateConnectionWithSecurity(uuid, scn, false, mtu, peer_bd_addr,
- client_handle, management_callback, 0),
- PORT_SUCCESS);
+ ASSERT_EQ(
+ RFCOMM_CreateConnectionWithSecurity(uuid, scn, false, mtu, peer_bd_addr, client_handle,
+ management_callback, 0, RfcommCfgInfo{}),
+ PORT_SUCCESS);
ASSERT_EQ(PORT_SetEventMaskAndCallback(*client_handle, PORT_EV_RXCHAR, event_callback),
PORT_SUCCESS);
osi_free(uih_pn_channel_3);
@@ -644,7 +643,7 @@ TEST_F(StackRfcommTest, DISABLED_TestConnectionCollision) {
// Prepare a server port
int status = RFCOMM_CreateConnectionWithSecurity(test_uuid, test_server_scn, true, test_mtu,
RawAddress::kAny, &server_handle,
- port_mgmt_cback_0, 0);
+ port_mgmt_cback_0, 0, RfcommCfgInfo{});
ASSERT_EQ(status, PORT_SUCCESS);
status = PORT_SetEventMaskAndCallback(server_handle, PORT_EV_RXCHAR, port_event_cback_0);
ASSERT_EQ(status, PORT_SUCCESS);
@@ -655,9 +654,9 @@ TEST_F(StackRfcommTest, DISABLED_TestConnectionCollision) {
EXPECT_CALL(l2cap_interface_, ConnectRequest(BT_PSM_RFCOMM, test_address))
.Times(1)
.WillOnce(Return(old_lcid));
- status =
- RFCOMM_CreateConnectionWithSecurity(test_uuid, test_peer_scn, false, test_mtu,
- test_address, &client_handle_1, port_mgmt_cback_1, 0);
+ status = RFCOMM_CreateConnectionWithSecurity(test_uuid, test_peer_scn, false, test_mtu,
+ test_address, &client_handle_1, port_mgmt_cback_1, 0,
+ RfcommCfgInfo{});
ASSERT_EQ(status, PORT_SUCCESS);
status = PORT_SetEventMaskAndCallback(client_handle_1, PORT_EV_RXCHAR, port_event_cback_1);
ASSERT_EQ(status, PORT_SUCCESS);
diff --git a/system/stack/test/rfcomm/stack_rfcomm_test_utils.cc b/system/stack/test/rfcomm/stack_rfcomm_test_utils.cc
index f11639bc0f..41ff6f7569 100644
--- a/system/stack/test/rfcomm/stack_rfcomm_test_utils.cc
+++ b/system/stack/test/rfcomm/stack_rfcomm_test_utils.cc
@@ -25,9 +25,6 @@
#include "stack/rfcomm/rfc_int.h"
#include "stack_test_packet_utils.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
namespace bluetooth {
namespace rfcomm {
@@ -57,7 +54,7 @@ uint8_t GetControlField(bool pf, uint8_t frame_type) {
return static_cast<uint8_t>(control.to_ulong());
}
-uint8_t GetFrameTypeFromControlField(uint8_t control_field) {
+static uint8_t GetFrameTypeFromControlField(uint8_t control_field) {
return static_cast<uint8_t>(control_field & ~(0b10000));
}
diff --git a/system/stack/test/sdp/stack_sdp_test.cc b/system/stack/test/sdp/stack_sdp_test.cc
index a60f808b4b..314ea02334 100644
--- a/system/stack/test/sdp/stack_sdp_test.cc
+++ b/system/stack/test/sdp/stack_sdp_test.cc
@@ -36,9 +36,6 @@
#define BT_DEFAULT_BUFFER_SIZE (4096 + 16)
#endif
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
@@ -130,7 +127,7 @@ TEST_F(StackSdpInitTest, sdp_service_search_request) {
ASSERT_EQ(p_ccb->con_state, tSDP_STATE::IDLE);
}
-tCONN_CB* find_ccb(uint16_t cid, tSDP_STATE state) {
+static tCONN_CB* find_ccb(uint16_t cid, tSDP_STATE state) {
uint16_t xx;
tCONN_CB* p_ccb;
@@ -188,7 +185,7 @@ TEST_F(StackSdpInitTest, sdp_service_search_request_queuing) {
ASSERT_EQ(p_ccb2->con_state, tSDP_STATE::IDLE);
}
-void sdp_callback(const RawAddress& /* bd_addr */, tSDP_RESULT result) {
+static void sdp_callback(const RawAddress& /* bd_addr */, tSDP_RESULT result) {
if (result == tSDP_STATUS::SDP_SUCCESS) {
ASSERT_TRUE(SDP_ServiceSearchRequest(addr, sdp_db, nullptr));
}
@@ -243,7 +240,7 @@ TEST_F(StackSdpInitTest, sdp_disc_wait_text) {
for (const auto& state : states) {
ASSERT_STREQ(state.second.c_str(), sdp_disc_wait_text(state.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[%d]", std::numeric_limits<uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max());
ASSERT_STREQ(unknown.c_str(),
sdp_disc_wait_text(static_cast<tSDP_DISC_WAIT>(std::numeric_limits<uint8_t>::max()))
.c_str());
@@ -277,7 +274,7 @@ TEST_F(StackSdpInitTest, sdp_flags_text) {
for (const auto& flag : flags) {
ASSERT_STREQ(flag.second.c_str(), sdp_flags_text(flag.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[%hhu]", std::numeric_limits<uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max());
ASSERT_STREQ(
unknown.c_str(),
sdp_flags_text(static_cast<tSDP_DISC_WAIT>(std::numeric_limits<uint8_t>::max())).c_str());
@@ -315,7 +312,7 @@ TEST_F(StackSdpInitTest, sdp_status_text) {
for (const auto& stat : status) {
ASSERT_STREQ(stat.second.c_str(), sdp_status_text(stat.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[%hu]", std::numeric_limits<uint16_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<uint16_t>::max());
ASSERT_STREQ(
unknown.c_str(),
sdp_status_text(static_cast<tSDP_STATUS>(std::numeric_limits<uint16_t>::max())).c_str());
diff --git a/system/stack/test/sdp/stack_sdp_utils_test.cc b/system/stack/test/sdp/stack_sdp_utils_test.cc
index 5a6b1fc9a1..e6a9ea9007 100644
--- a/system/stack/test/sdp/stack_sdp_utils_test.cc
+++ b/system/stack/test/sdp/stack_sdp_utils_test.cc
@@ -22,6 +22,7 @@
#include "btif/include/btif_storage.h"
#include "btif/include/stack_manager_t.h"
#include "device/include/interop.h"
+#include "device/include/interop_config.h"
#include "mock_btif_config.h"
#include "osi/include/allocator.h"
#include "profile/avrcp/avrcp_config.h"
@@ -49,9 +50,6 @@
#define HFP_PROFILE_MINOR_VERSION_6 0x06
#define HFP_PROFILE_MINOR_VERSION_7 0x07
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
static int L2CA_ConnectReqWithSecurity_cid = 0x42;
static RawAddress addr = RawAddress({0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6});
static tSDP_DISCOVERY_DB* sdp_db = nullptr;
@@ -64,9 +62,6 @@ using ::testing::ReturnArg;
using ::testing::SaveArg;
using ::testing::SetArrayArgument;
-void sdp_callback(const RawAddress& bd_addr, tSDP_RESULT result);
-tCONN_CB* find_ccb(uint16_t cid, uint8_t state);
-
namespace {
// convenience mock
class IopMock {
@@ -178,32 +173,32 @@ tSDP_ATTRIBUTE hfp_attr = {
.type = 0,
};
-void set_hfp_attr(uint32_t len, uint16_t id, uint16_t uuid) {
+static void set_hfp_attr(uint32_t len, uint16_t id, uint16_t uuid) {
hfp_attr.value_ptr[4] = uuid;
hfp_attr.len = len;
hfp_attr.id = id;
}
-void set_avrcp_feat_attr(uint32_t len, uint16_t id, uint16_t feature) {
+static void set_avrcp_feat_attr(uint32_t len, uint16_t id, uint16_t feature) {
UINT16_TO_BE_FIELD(avrc_feat_value, feature);
avrcp_feat_attr.len = len;
avrcp_feat_attr.id = id;
}
-void set_avrcp_attr(uint32_t len, uint16_t id, uint16_t uuid, uint16_t version) {
+static void set_avrcp_attr(uint32_t len, uint16_t id, uint16_t uuid, uint16_t version) {
UINT16_TO_BE_FIELD(avrc_value + 3, uuid);
UINT16_TO_BE_FIELD(avrc_value + 6, version);
avrcp_attr.len = len;
avrcp_attr.id = id;
}
-uint16_t get_avrc_target_version(tSDP_ATTRIBUTE* p_attr) {
+static uint16_t get_avrc_target_version(tSDP_ATTRIBUTE* p_attr) {
uint8_t* p_version = p_attr->value_ptr + 6;
uint16_t version = (((uint16_t)(*(p_version))) << 8) + ((uint16_t)(*((p_version) + 1)));
return version;
}
-uint16_t get_avrc_target_feature(tSDP_ATTRIBUTE* p_attr) {
+static uint16_t get_avrc_target_feature(tSDP_ATTRIBUTE* p_attr) {
uint8_t* p_feature = p_attr->value_ptr;
uint16_t feature = (((uint16_t)(*(p_feature))) << 8) + ((uint16_t)(*((p_feature) + 1)));
return feature;
diff --git a/system/stack/test/stack_avdtp_test.cc b/system/stack/test/stack_avdtp_test.cc
index 8c9372ec93..676718a22a 100644
--- a/system/stack/test/stack_avdtp_test.cc
+++ b/system/stack/test/stack_avdtp_test.cc
@@ -24,10 +24,13 @@
#include "osi/include/allocator.h"
#include "stack/avdt/avdt_int.h"
#include "stack/include/avdt_api.h"
+#include "stack/include/main_thread.h"
#include "stack/test/common/mock_stack_avdt_msg.h"
#include "test/common/mock_functions.h"
#include "types/raw_address.h"
+bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
+
class StackAvdtpTest : public ::testing::Test {
protected:
StackAvdtpTest() = default;
diff --git a/system/stack/test/stack_rnr_test.cc b/system/stack/test/stack_rnr_test.cc
index e2b0b3cb73..b2c4523e6c 100644
--- a/system/stack/test/stack_rnr_test.cc
+++ b/system/stack/test/stack_rnr_test.cc
@@ -27,13 +27,6 @@
#include "test/mock/mock_osi_thread.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
-extern tBTM_CB btm_cb;
-
-bool ble_evt_type_is_connectable(uint16_t /* evt_type */) { return true; }
-
tBTM_CB btm_cb;
namespace {
diff --git a/system/stack/test/stack_smp_test.cc b/system/stack/test/stack_smp_test.cc
index c7de45814c..41d61e738b 100644
--- a/system/stack/test/stack_smp_test.cc
+++ b/system/stack/test/stack_smp_test.cc
@@ -35,39 +35,36 @@
#include "types/hci_role.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using testing::StrEq;
tBTM_CB btm_cb;
const std::string kSmpOptions("mock smp options");
const std::string kBroadcastAudioConfigOptions("mock broadcast audio config options");
-bool get_pts_avrcp_test(void) { return false; }
-bool get_pts_secure_only_mode(void) { return false; }
-bool get_pts_conn_updates_disabled(void) { return false; }
-bool get_pts_crosskey_sdp_disable(void) { return false; }
-const std::string* get_pts_smp_options(void) { return &kSmpOptions; }
-int get_pts_smp_failure_case(void) { return 123; }
-bool get_pts_force_eatt_for_notifications(void) { return false; }
-bool get_pts_connect_eatt_unconditionally(void) { return false; }
-bool get_pts_connect_eatt_before_encryption(void) { return false; }
-bool get_pts_unencrypt_broadcast(void) { return false; }
-bool get_pts_eatt_peripheral_collision_support(void) { return false; }
-bool get_pts_use_eatt_for_all_services(void) { return false; }
-bool get_pts_force_le_audio_multiple_contexts_metadata(void) { return false; }
-bool get_pts_l2cap_ecoc_upper_tester(void) { return false; }
-int get_pts_l2cap_ecoc_min_key_size(void) { return -1; }
-int get_pts_l2cap_ecoc_initial_chan_cnt(void) { return -1; }
-bool get_pts_l2cap_ecoc_connect_remaining(void) { return false; }
-int get_pts_l2cap_ecoc_send_num_of_sdu(void) { return -1; }
-bool get_pts_l2cap_ecoc_reconfigure(void) { return false; }
-const std::string* get_pts_broadcast_audio_config_options(void) {
+static bool get_pts_avrcp_test(void) { return false; }
+static bool get_pts_secure_only_mode(void) { return false; }
+static bool get_pts_conn_updates_disabled(void) { return false; }
+static bool get_pts_crosskey_sdp_disable(void) { return false; }
+static const std::string* get_pts_smp_options(void) { return &kSmpOptions; }
+static int get_pts_smp_failure_case(void) { return 123; }
+static bool get_pts_force_eatt_for_notifications(void) { return false; }
+static bool get_pts_connect_eatt_unconditionally(void) { return false; }
+static bool get_pts_connect_eatt_before_encryption(void) { return false; }
+static bool get_pts_unencrypt_broadcast(void) { return false; }
+static bool get_pts_eatt_peripheral_collision_support(void) { return false; }
+static bool get_pts_use_eatt_for_all_services(void) { return false; }
+static bool get_pts_force_le_audio_multiple_contexts_metadata(void) { return false; }
+static bool get_pts_l2cap_ecoc_upper_tester(void) { return false; }
+static int get_pts_l2cap_ecoc_min_key_size(void) { return -1; }
+static int get_pts_l2cap_ecoc_initial_chan_cnt(void) { return -1; }
+static bool get_pts_l2cap_ecoc_connect_remaining(void) { return false; }
+static int get_pts_l2cap_ecoc_send_num_of_sdu(void) { return -1; }
+static bool get_pts_l2cap_ecoc_reconfigure(void) { return false; }
+static const std::string* get_pts_broadcast_audio_config_options(void) {
return &kBroadcastAudioConfigOptions;
}
-bool get_pts_le_audio_disable_ases_before_stopping(void) { return false; }
-config_t* get_all(void) { return nullptr; }
+static bool get_pts_le_audio_disable_ases_before_stopping(void) { return false; }
+static config_t* get_all(void) { return nullptr; }
const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; }
stack_config_t mock_stack_config{
@@ -127,21 +124,7 @@ const stack_config_t* stack_config_get_interface(void) { return &mock_stack_conf
* MSB on the right.
*/
-Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb, tBLE_ADDR_TYPE remote_bd_addr_type);
-
-Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda);
-
-tSMP_STATUS smp_calculate_confirm(tSMP_CB* p_cb, const Octet16& rand, Octet16* output);
-
-void dump_uint128(const Octet16& a, char* buffer) {
- for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
- snprintf(buffer, 3, "%02x", a[i]);
- buffer += 2;
- }
- *buffer = '\0';
-}
-
-void dump_uint128_reverse(const Octet16& a, char* buffer) {
+static void dump_uint128_reverse(const Octet16& a, char* buffer) {
for (int i = (int)(OCTET16_LEN - 1); i >= 0; --i) {
snprintf(buffer, 3, "%02x", a[i]);
buffer += 2;
@@ -149,22 +132,6 @@ void dump_uint128_reverse(const Octet16& a, char* buffer) {
*buffer = '\0';
}
-void print_uint128(const Octet16& a) {
- for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
- printf("%02x", a[i]);
- }
- printf("\n");
-}
-
-Octet16 parse_uint128(const char* input) {
- Octet16 output{0};
- for (unsigned int count = 0; count < OCTET16_LEN; count++) {
- sscanf(input, "%2hhx", &output[count]);
- input += 2;
- }
- return output;
-}
-
class SmpCalculateConfirmTest : public testing::Test {
protected:
tSMP_CB p_cb_;
@@ -422,7 +389,7 @@ TEST(SmpStatusText, smp_status_text) {
for (const auto& stat : status) {
ASSERT_STREQ(stat.second.c_str(), smp_status_text(stat.first).c_str());
}
- auto unknown = base::StringPrintf("UNKNOWN[%hhu]", std::numeric_limits<uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max());
ASSERT_STREQ(
unknown.c_str(),
smp_status_text(static_cast<tSMP_STATUS>(std::numeric_limits<uint8_t>::max())).c_str());
diff --git a/system/test/Android.bp b/system/test/Android.bp
index d4a1a767eb..c5a3b0c2d6 100644
--- a/system/test/Android.bp
+++ b/system/test/Android.bp
@@ -628,7 +628,10 @@ cc_defaults {
target: {
android: {
test_config_template: ":BluetoothTestConfigTemplate",
- test_suites: ["mts-bluetooth"],
+ test_suites: [
+ "mts-bluetooth",
+ "mts-bt",
+ ],
},
},
compile_multilib: "both",
diff --git a/system/test/headless/Android.bp b/system/test/headless/Android.bp
index ec61ea012f..09a08f8fec 100644
--- a/system/test/headless/Android.bp
+++ b/system/test/headless/Android.bp
@@ -82,7 +82,6 @@ cc_binary {
"lib-bt-packets-base",
"libFraunhoferAAC",
"libbase",
- "libbluetooth-dumpsys",
"libbluetooth-types",
"libbluetooth_core_rs",
"libbluetooth_crypto_toolbox",
diff --git a/system/test/headless/bt_stack_info.cc b/system/test/headless/bt_stack_info.cc
index 300dbf62b7..f711dbf312 100644
--- a/system/test/headless/bt_stack_info.cc
+++ b/system/test/headless/bt_stack_info.cc
@@ -49,11 +49,10 @@ void BtStackInfo::DumpsysLite() {
LOG_CONSOLE("jni_pid:%u", jni_pid_);
int fd = STDIN_FILENO;
- const char** arguments = nullptr;
connection_manager::dump(fd);
PAN_Dumpsys(fd);
DumpsysHid(fd);
DumpsysBtaDm(fd);
- bluetooth::shim::Dump(fd, arguments);
+ bluetooth::shim::Dump(fd);
}
diff --git a/system/test/mock/mock_bta_jv_api.cc b/system/test/mock/mock_bta_jv_api.cc
index cf7fd4645e..ec913b5b01 100644
--- a/system/test/mock/mock_bta_jv_api.cc
+++ b/system/test/mock/mock_bta_jv_api.cc
@@ -76,14 +76,14 @@ tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t /* handle */, uint32_t /* rfcomm_slot_
tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC /* sec_mask */, uint8_t /* remote_scn */,
const RawAddress& /* peer_bd_addr */,
tBTA_JV_RFCOMM_CBACK* /* p_cback */,
- uint32_t /* rfcomm_slot_id */) {
+ uint32_t /* rfcomm_slot_id */, RfcommCfgInfo /* cfg */) {
inc_func_call_count(__func__);
return tBTA_JV_STATUS::SUCCESS;
}
tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC /* sec_mask */, uint8_t /* local_scn */,
uint8_t /* max_session */,
tBTA_JV_RFCOMM_CBACK* /* p_cback */,
- uint32_t /* rfcomm_slot_id */) {
+ uint32_t /* rfcomm_slot_id */, RfcommCfgInfo /* cfg */) {
inc_func_call_count(__func__);
return tBTA_JV_STATUS::SUCCESS;
}
diff --git a/system/test/mock/mock_btif_sock_l2cap.cc b/system/test/mock/mock_btif_sock_l2cap.cc
new file mode 100644
index 0000000000..41f19f8cd0
--- /dev/null
+++ b/system/test/mock/mock_btif_sock_l2cap.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 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.
+ */
+/*
+ * Generated mock file from original source file
+ * Functions generated:13
+ *
+ * mockcify.pl ver 0.7.1
+ */
+
+// Mock include file to share data between tests and mock
+#include "test/mock/mock_btif_sock_l2cap.h"
+
+#include <cstdint>
+
+#include "test/common/mock_functions.h"
+
+// TODO(b/369381361) Enfore -Wmissing-prototypes
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+
+// Original usings
+
+// Mocked internal structures, if any
+
+namespace test {
+namespace mock {
+namespace btif_sock_l2cap {
+
+// Function state capture and return values, if needed
+struct on_btsocket_l2cap_close on_btsocket_l2cap_close;
+struct on_btsocket_l2cap_opened_complete on_btsocket_l2cap_opened_complete;
+
+} // namespace btif_sock_l2cap
+} // namespace mock
+} // namespace test
+
+// Mocked function return values, if any
+namespace test {
+namespace mock {
+namespace btif_sock_l2cap {} // namespace btif_sock_l2cap
+} // namespace mock
+} // namespace test
+
+// Mocked functions, if any
+void on_btsocket_l2cap_close(uint64_t socket_id) {
+ inc_func_call_count(__func__);
+ test::mock::btif_sock_l2cap::on_btsocket_l2cap_close(socket_id);
+}
+void on_btsocket_l2cap_opened_complete(uint64_t socket_id, bool success) {
+ inc_func_call_count(__func__);
+ test::mock::btif_sock_l2cap::on_btsocket_l2cap_opened_complete(socket_id, success);
+}
+// Mocked functions complete
+// END mockcify generation
diff --git a/system/test/mock/mock_btif_sock_l2cap.h b/system/test/mock/mock_btif_sock_l2cap.h
new file mode 100644
index 0000000000..f883f8bf1f
--- /dev/null
+++ b/system/test/mock/mock_btif_sock_l2cap.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2023 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
+
+/*
+ * Generated mock file from original source file
+ * Functions generated:13
+ *
+ * mockcify.pl ver 0.7.1
+ */
+
+#include <cstdint>
+#include <functional>
+
+// Original included files, if any
+#include <cstring>
+
+// Original usings
+
+// Mocked compile conditionals, if any
+
+namespace test {
+namespace mock {
+namespace btif_sock_l2cap {
+
+// Shared state between mocked functions and tests
+// Name: on_btsocket_l2cap_close
+// Params: uint64_t socket_id
+// Return: void
+struct on_btsocket_l2cap_close {
+ std::function<void(uint64_t socket_id)> body{[](uint64_t /* socket_id */) {}};
+ void operator()(uint64_t socket_id) { body(socket_id); }
+};
+extern struct on_btsocket_l2cap_close on_btsocket_l2cap_close;
+
+// Name: on_btsocket_l2cap_opened_complete
+// Params: uint64_t socket_id, bool success
+// Return: void
+struct on_btsocket_l2cap_opened_complete {
+ std::function<void(uint64_t socket_id, bool success)> body{
+ [](uint64_t /* socket_id */, bool /* success */) {}};
+ void operator()(uint64_t socket_id, bool success) { body(socket_id, success); }
+};
+extern struct on_btsocket_l2cap_opened_complete on_btsocket_l2cap_opened_complete;
+
+} // namespace btif_sock_l2cap
+} // namespace mock
+} // namespace test
+
+// END mockcify generation
diff --git a/system/test/mock/mock_btif_sock_rfc.cc b/system/test/mock/mock_btif_sock_rfc.cc
index 49b5b117fa..6ca7512418 100644
--- a/system/test/mock/mock_btif_sock_rfc.cc
+++ b/system/test/mock/mock_btif_sock_rfc.cc
@@ -49,6 +49,8 @@ struct btsock_rfc_disconnect btsock_rfc_disconnect;
struct btsock_rfc_init btsock_rfc_init;
struct btsock_rfc_listen btsock_rfc_listen;
struct btsock_rfc_signaled btsock_rfc_signaled;
+struct on_btsocket_rfc_close on_btsocket_rfc_close;
+struct on_btsocket_rfc_opened_complete on_btsocket_rfc_opened_complete;
} // namespace btif_sock_rfc
} // namespace mock
@@ -120,5 +122,13 @@ void btsock_rfc_signaled(int fd, int flags, uint32_t id) {
inc_func_call_count(__func__);
test::mock::btif_sock_rfc::btsock_rfc_signaled(fd, flags, id);
}
+void on_btsocket_rfc_close(uint64_t socket_id) {
+ inc_func_call_count(__func__);
+ test::mock::btif_sock_rfc::on_btsocket_rfc_close(socket_id);
+}
+void on_btsocket_rfc_opened_complete(uint64_t socket_id, bool success) {
+ inc_func_call_count(__func__);
+ test::mock::btif_sock_rfc::on_btsocket_rfc_opened_complete(socket_id, success);
+}
// Mocked functions complete
// END mockcify generation
diff --git a/system/test/mock/mock_btif_sock_rfc.h b/system/test/mock/mock_btif_sock_rfc.h
index fa0bfe4373..59f296f016 100644
--- a/system/test/mock/mock_btif_sock_rfc.h
+++ b/system/test/mock/mock_btif_sock_rfc.h
@@ -173,6 +173,25 @@ struct btsock_rfc_signaled {
};
extern struct btsock_rfc_signaled btsock_rfc_signaled;
+// Name: on_btsocket_rfc_close
+// Params: uint64_t socket_id
+// Return: void
+struct on_btsocket_rfc_close {
+ std::function<void(uint64_t socket_id)> body{[](uint64_t /* socket_id */) {}};
+ void operator()(uint64_t socket_id) { body(socket_id); }
+};
+extern struct on_btsocket_rfc_close on_btsocket_rfc_close;
+
+// Name: on_btsocket_rfc_opened_complete
+// Params: uint64_t socket_id, bool success
+// Return: void
+struct on_btsocket_rfc_opened_complete {
+ std::function<void(uint64_t socket_id, bool success)> body{
+ [](uint64_t /* socket_id */, bool /* success */) {}};
+ void operator()(uint64_t socket_id, bool success) { body(socket_id, success); }
+};
+extern struct on_btsocket_rfc_opened_complete on_btsocket_rfc_opened_complete;
+
} // namespace btif_sock_rfc
} // namespace mock
} // namespace test
diff --git a/system/test/mock/mock_main_shim_acl.cc b/system/test/mock/mock_main_shim_acl.cc
index 831be689d6..bd27e6927f 100644
--- a/system/test/mock/mock_main_shim_acl.cc
+++ b/system/test/mock/mock_main_shim_acl.cc
@@ -47,7 +47,7 @@ void DumpsysNeighbor(int /* fd */) { inc_func_call_count(__func__); }
void shim::Acl::Dump(int /* fd */) const { inc_func_call_count(__func__); }
shim::Acl::Acl(os::Handler* /* handler */, const acl_interface_t& acl_interface,
- uint8_t /* max_acceptlist_size */, uint8_t /* max_address_resolution_size */)
+ uint8_t /* max_address_resolution_size */)
: acl_interface_(acl_interface) {
inc_func_call_count(__func__);
}
diff --git a/system/test/mock/mock_main_shim_dumpsys.cc b/system/test/mock/mock_main_shim_dumpsys.cc
index 77b3bfc06a..16e3a83eed 100644
--- a/system/test/mock/mock_main_shim_dumpsys.cc
+++ b/system/test/mock/mock_main_shim_dumpsys.cc
@@ -20,13 +20,12 @@
*/
#include "main/shim/dumpsys.h"
-#include "shim/dumpsys.h"
#include "test/common/mock_functions.h"
void bluetooth::shim::RegisterDumpsysFunction(const void* /* token */, DumpsysFunction /* func */) {
inc_func_call_count(__func__);
}
-void bluetooth::shim::Dump(int /* fd */, const char** /* args */) { inc_func_call_count(__func__); }
+void bluetooth::shim::Dump(int /* fd */) { inc_func_call_count(__func__); }
void bluetooth::shim::UnregisterDumpsysFunction(const void* /* token */) {
inc_func_call_count(__func__);
}
diff --git a/system/test/mock/mock_main_shim_entry.cc b/system/test/mock/mock_main_shim_entry.cc
index 72054dad81..291cb0c0fd 100644
--- a/system/test/mock/mock_main_shim_entry.cc
+++ b/system/test/mock/mock_main_shim_entry.cc
@@ -20,6 +20,7 @@
#include "hci/hci_interface.h"
#include "hci/le_advertising_manager_mock.h"
#include "hci/le_scanning_manager_mock.h"
+#include "lpp/lpp_offload_interface_mock.h"
#include "main/shim/entry.h"
#include "os/handler.h"
#include "storage/storage_module.h"
@@ -30,7 +31,6 @@ namespace testing {
MockAclManager* mock_acl_manager_{nullptr};
MockControllerInterface* mock_controller_{nullptr};
-shim::Dumpsys* shim_dumpsys_ = {};
HciInterface* mock_hci_layer_{nullptr};
os::Handler* mock_gd_shim_handler_{nullptr};
MockLeAdvertisingManager* mock_le_advertising_manager_{nullptr};
@@ -40,11 +40,14 @@ MockDistanceMeasurementManager* mock_distance_measurement_manager_{nullptr};
} // namespace testing
} // namespace hci
+namespace lpp::testing {
+MockLppOffloadInterface* mock_lpp_offload_interface_{nullptr};
+} // namespace lpp::testing
+
class Dumpsys;
namespace shim {
-Dumpsys* GetDumpsys() { return hci::testing::shim_dumpsys_; }
hci::AclManager* GetAclManager() { return hci::testing::mock_acl_manager_; }
hci::ControllerInterface* GetController() { return hci::testing::mock_controller_; }
hci::HciInterface* GetHciLayer() { return hci::testing::mock_hci_layer_; }
@@ -59,6 +62,9 @@ storage::StorageModule* GetStorage() { return nullptr; }
metrics::CounterMetrics* GetCounterMetrics() { return nullptr; }
hci::MsftExtensionManager* GetMsftExtensionManager() { return nullptr; }
hci::RemoteNameRequestModule* GetRemoteNameRequest() { return nullptr; }
+lpp::LppOffloadInterface* GetLppOffloadManager() {
+ return lpp::testing::mock_lpp_offload_interface_;
+}
} // namespace shim
} // namespace bluetooth
diff --git a/system/test/mock/mock_main_shim_entry.h b/system/test/mock/mock_main_shim_entry.h
index cde3f778f7..d82342e1a6 100644
--- a/system/test/mock/mock_main_shim_entry.h
+++ b/system/test/mock/mock_main_shim_entry.h
@@ -22,7 +22,6 @@
#include "hci/hci_interface.h"
#include "hci/le_advertising_manager_mock.h"
#include "hci/le_scanning_manager_mock.h"
-#include "shim/dumpsys.h"
namespace bluetooth {
namespace hci {
@@ -30,7 +29,6 @@ namespace testing {
extern MockAclManager* mock_acl_manager_;
extern MockControllerInterface* mock_controller_;
-extern std::function<shim::Dumpsys*()> shim_dumpsys_;
extern HciInterface* mock_hci_layer_;
extern os::Handler* mock_gd_shim_handler_;
extern MockLeAdvertisingManager* mock_le_advertising_manager_;
diff --git a/system/test/mock/mock_main_shim_metrics_api.cc b/system/test/mock/mock_main_shim_metrics_api.cc
index ffe5a46f15..841cd759a9 100644
--- a/system/test/mock/mock_main_shim_metrics_api.cc
+++ b/system/test/mock/mock_main_shim_metrics_api.cc
@@ -55,6 +55,9 @@ struct LogMetricClassicPairingEvent LogMetricClassicPairingEvent;
struct LogMetricSdpAttribute LogMetricSdpAttribute;
struct LogMetricSocketConnectionState LogMetricSocketConnectionState;
struct LogMetricManufacturerInfo LogMetricManufacturerInfo;
+struct LogMetricLeConnectionStatus LogMetricLeConnectionStatus;
+struct LogMetricLeDeviceInAcceptList LogMetricLeDeviceInAcceptList;
+struct LogMetricLeConnectionLifecycle LogMetricLeConnectionLifecycle;
} // namespace main_shim_metrics_api
} // namespace mock
@@ -190,4 +193,18 @@ bool bluetooth::shim::CountCounterMetrics(int32_t /* key */, int64_t /* count */
inc_func_call_count(__func__);
return false;
}
+void bluetooth::shim::LogMetricLeConnectionStatus(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason) {
+ inc_func_call_count(__func__);
+ test::mock::main_shim_metrics_api::LogMetricLeConnectionStatus(address, is_connect, reason);
+}
+void bluetooth::shim::LogMetricLeDeviceInAcceptList(bluetooth::hci::Address address, bool is_add) {
+ inc_func_call_count(__func__);
+ test::mock::main_shim_metrics_api::LogMetricLeDeviceInAcceptList(address, is_add);
+}
+void bluetooth::shim::LogMetricLeConnectionLifecycle(bluetooth::hci::Address address,
+ bool is_connect, bool is_direct) {
+ inc_func_call_count(__func__);
+ test::mock::main_shim_metrics_api::LogMetricLeConnectionLifecycle(address, is_connect, is_direct);
+}
// END mockcify generation
diff --git a/system/test/mock/mock_main_shim_metrics_api.h b/system/test/mock/mock_main_shim_metrics_api.h
index 401b5a05ef..f5f177b5f4 100644
--- a/system/test/mock/mock_main_shim_metrics_api.h
+++ b/system/test/mock/mock_main_shim_metrics_api.h
@@ -28,6 +28,8 @@
// Original included files, if any
// #include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h>
+#include "hci/address.h"
+#include "hci/hci_packets.h"
#include "os/metrics.h"
#include "types/raw_address.h"
@@ -312,6 +314,42 @@ struct LogMetricManufacturerInfo {
}
};
extern struct LogMetricManufacturerInfo LogMetricManufacturerInfo;
+// Name: LogMetricLeConnectionStatus
+// Params: bluetooth::hci::Address address, bool is_connect, bluetooth::hci::ErrorCode reason
+// Returns: void
+struct LogMetricLeConnectionStatus {
+ std::function<void(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason)>
+ body{[](bluetooth::hci::Address /* address */, bool /* is_connect */,
+ bluetooth::hci::ErrorCode /* reason */) {}};
+ void operator()(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason) {
+ body(address, is_connect, reason);
+ }
+};
+extern struct LogMetricLeConnectionStatus LogMetricLeConnectionStatus;
+// Name: LogMetricLeDeviceInAcceptList
+// Params: bluetooth::hci::Address address, bool is_add
+// Returns: void
+struct LogMetricLeDeviceInAcceptList {
+ std::function<void(bluetooth::hci::Address address, bool is_add)> body{
+ [](bluetooth::hci::Address /* address */, bool /* is_add */) {}};
+ void operator()(bluetooth::hci::Address address, bool is_add) { body(address, is_add); }
+};
+extern struct LogMetricLeDeviceInAcceptList LogMetricLeDeviceInAcceptList;
+
+// Name: LogMetricLeConnectionLifecycle
+// Params: bluetooth::hci::Address address, bool is_connect, bool is_direct
+// Returns: void
+struct LogMetricLeConnectionLifecycle {
+ std::function<void(bluetooth::hci::Address address, bool is_connect, bool is_direct)> body{
+ [](bluetooth::hci::Address /* address */, bool /* is_connect */, bool /* is_direct */) {
+ }};
+ void operator()(bluetooth::hci::Address address, bool is_connect, bool is_direct) {
+ body(address, is_connect, is_direct);
+ }
+};
+extern struct LogMetricLeConnectionLifecycle LogMetricLeConnectionLifecycle;
} // namespace main_shim_metrics_api
} // namespace mock
diff --git a/system/test/mock/mock_main_shim_stack.cc b/system/test/mock/mock_main_shim_stack.cc
index 04543301ee..03ec09a1b3 100644
--- a/system/test/mock/mock_main_shim_stack.cc
+++ b/system/test/mock/mock_main_shim_stack.cc
@@ -37,17 +37,9 @@ void Stack::Stop() {}
bool Stack::IsRunning() { return stack_thread_ != nullptr; }
-StackManager* Stack::GetStackManager() { return nullptr; }
-
-const StackManager* Stack::GetStackManager() const { return nullptr; }
-
Acl* Stack::GetAcl() { return testing::acl_; }
os::Handler* Stack::GetHandler() { return stack_handler_; }
-bool Stack::IsDumpsysModuleStarted() const { return false; }
-
-bool Stack::LockForDumpsys(std::function<void()> /* dumpsys_callback */) { return false; }
-
} // namespace shim
} // namespace bluetooth
diff --git a/system/test/mock/mock_stack_connection_manager.cc b/system/test/mock/mock_stack_connection_manager.cc
index 97cd160854..5f4d045e63 100644
--- a/system/test/mock/mock_stack_connection_manager.cc
+++ b/system/test/mock/mock_stack_connection_manager.cc
@@ -44,13 +44,8 @@ bool connection_manager::background_connect_remove(uint8_t /* app_id */,
return false;
}
-bool connection_manager::create_le_connection(uint8_t /* id */, const RawAddress& /* bd_addr */,
- tBLE_ADDR_TYPE /* addr_type */) {
- inc_func_call_count(__func__);
- return false;
-}
-
-bool connection_manager::direct_connect_add(uint8_t /* app_id */, const RawAddress& /* address */) {
+bool connection_manager::direct_connect_add(uint8_t /* app_id */, const RawAddress& /* address */,
+ tBLE_ADDR_TYPE /* addr_type */) {
inc_func_call_count(__func__);
return false;
}
diff --git a/system/test/mock/mock_stack_gap_conn.cc b/system/test/mock/mock_stack_gap_conn.cc
index 19034a9fec..07193c9130 100644
--- a/system/test/mock/mock_stack_gap_conn.cc
+++ b/system/test/mock/mock_stack_gap_conn.cc
@@ -61,4 +61,16 @@ uint16_t GAP_ConnWriteData(uint16_t /* gap_handle */, BT_HDR* /* msg */) {
inc_func_call_count(__func__);
return 0;
}
+bool GAP_GetLeChannelInfo(uint16_t /* gap_handle */, uint16_t* /*remote_mtu */,
+ uint16_t* /* local_mps */, uint16_t* /* remote_mps */,
+ uint16_t* /* local_credit */, uint16_t* /* remote_credit */,
+ uint16_t* /* local_cid */, uint16_t* /* remote_cid */,
+ uint16_t* /* acl_handle */) {
+ inc_func_call_count(__func__);
+ return false;
+}
+bool GAP_IsTransportLe(uint16_t /* gap_handle */) {
+ inc_func_call_count(__func__);
+ return false;
+}
void GAP_Init(void) { inc_func_call_count(__func__); }
diff --git a/system/test/mock/mock_stack_hidh.cc b/system/test/mock/mock_stack_hidh.cc
index 15b16a4ae8..607fa16753 100644
--- a/system/test/mock/mock_stack_hidh.cc
+++ b/system/test/mock/mock_stack_hidh.cc
@@ -27,9 +27,6 @@
#include "test/common/mock_functions.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
tHID_STATUS HID_HostAddDev(const RawAddress& /* addr */, uint16_t /* attr_mask */,
uint8_t* /* handle */) {
inc_func_call_count(__func__);
@@ -70,7 +67,3 @@ tHID_STATUS HID_HostWriteDev(uint8_t /* dev_handle */, uint8_t /* t_type */, uin
return HID_SUCCESS;
}
void HID_HostInit(void) { inc_func_call_count(__func__); }
-void hidh_get_str_attr(tSDP_DISC_REC* /* p_rec */, uint16_t /* attr_id */, uint16_t /* max_len */,
- char* /* str */) {
- inc_func_call_count(__func__);
-}
diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc
index b8f3f4e227..de117f06a9 100644
--- a/system/test/mock/mock_stack_l2cap_api.cc
+++ b/system/test/mock/mock_stack_l2cap_api.cc
@@ -75,6 +75,8 @@ struct L2CA_SetMediaStreamChannel L2CA_SetMediaStreamChannel;
struct L2CA_isMediaChannel L2CA_isMediaChannel;
struct L2CA_LeCreditDefault L2CA_LeCreditDefault;
struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
+struct L2CA_GetAclHandle L2CA_GetAclHandle;
+struct L2CA_GetLocalMtu L2CA_GetLocalMtu;
} // namespace stack_l2cap_api
} // namespace mock
@@ -250,6 +252,14 @@ uint16_t L2CA_LeCreditThreshold() {
inc_func_call_count(__func__);
return test::mock::stack_l2cap_api::L2CA_LeCreditThreshold();
}
+bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) {
+ inc_func_call_count(__func__);
+ return test::mock::stack_l2cap_api::L2CA_GetAclHandle(lcid, acl_handle);
+}
+bool L2CA_GetLocalMtu(uint16_t lcid, uint16_t* local_mtu) {
+ inc_func_call_count(__func__);
+ return test::mock::stack_l2cap_api::L2CA_GetLocalMtu(lcid, local_mtu);
+}
// END mockcify generation
diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h
index 40d746ecd3..3f2e6dc72f 100644
--- a/system/test/mock/mock_stack_l2cap_api.h
+++ b/system/test/mock/mock_stack_l2cap_api.h
@@ -457,6 +457,26 @@ struct L2CA_LeCreditThreshold {
};
extern struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
+// Name: L2CA_GetAclHandle
+// Params: uint16_t lcid, uint16_t* acl_handle
+// Returns: bool
+struct L2CA_GetAclHandle {
+ std::function<bool(uint16_t lcid, uint16_t* acl_handle)> body{
+ [](uint16_t /* lcid */, uint16_t* /* acl_handle */) { return false; }};
+ bool operator()(uint16_t lcid, uint16_t* acl_handle) { return body(lcid, acl_handle); }
+};
+extern struct L2CA_GetAclHandle L2CA_GetAclHandle;
+
+// Name: L2CA_GetLocalMtu
+// Params: uint16_t lcid, uint16_t* local_mtu
+// Returns: bool
+struct L2CA_GetLocalMtu {
+ std::function<bool(uint16_t lcid, uint16_t* local_mtu)> body{
+ [](uint16_t /* lcid */, uint16_t* /* local_mtu */) { return false; }};
+ bool operator()(uint16_t lcid, uint16_t* local_mtu) { return body(lcid, local_mtu); }
+};
+extern struct L2CA_GetLocalMtu L2CA_GetLocalMtu;
+
} // namespace stack_l2cap_api
} // namespace mock
} // namespace test
diff --git a/system/test/mock/mock_stack_l2cap_ble.cc b/system/test/mock/mock_stack_l2cap_ble.cc
index 7dcd2f6bf0..6224446eb0 100644
--- a/system/test/mock/mock_stack_l2cap_ble.cc
+++ b/system/test/mock/mock_stack_l2cap_ble.cc
@@ -44,6 +44,7 @@ struct L2CA_LockBleConnParamsForServiceDiscovery L2CA_LockBleConnParamsForServic
struct L2CA_LockBleConnParamsForProfileConnection L2CA_LockBleConnParamsForProfileConnection;
struct L2CA_ConsolidateParams L2CA_ConsolidateParams;
struct L2CA_GetBleConnRole L2CA_GetBleConnRole;
+struct L2CA_GetBleConnInterval L2CA_GetBleConnInterval;
struct l2cble_notify_le_connection l2cble_notify_le_connection;
struct l2cble_conn_comp l2cble_conn_comp;
struct l2cble_process_conn_update_evt l2cble_process_conn_update_evt;
@@ -93,6 +94,10 @@ hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) {
inc_func_call_count(__func__);
return test::mock::stack_l2cap_ble::L2CA_GetBleConnRole(bd_addr);
}
+uint16_t L2CA_GetBleConnInterval(const RawAddress& bd_addr) {
+ inc_func_call_count(__func__);
+ return test::mock::stack_l2cap_ble::L2CA_GetBleConnInterval(bd_addr);
+}
void l2cble_notify_le_connection(const RawAddress& bda) {
inc_func_call_count(__func__);
test::mock::stack_l2cap_ble::l2cble_notify_le_connection(bda);
diff --git a/system/test/mock/mock_stack_l2cap_ble.h b/system/test/mock/mock_stack_l2cap_ble.h
index c5c3e45a1d..913a04f5e2 100644
--- a/system/test/mock/mock_stack_l2cap_ble.h
+++ b/system/test/mock/mock_stack_l2cap_ble.h
@@ -89,6 +89,15 @@ struct L2CA_GetBleConnRole {
hci_role_t operator()(const RawAddress& bd_addr) { return body(bd_addr); }
};
extern struct L2CA_GetBleConnRole L2CA_GetBleConnRole;
+// Name: L2CA_GetBleConnInterval
+// Params: const RawAddress& bd_addr
+// Returns: uint16_t
+struct L2CA_GetBleConnInterval {
+ std::function<uint16_t(const RawAddress& bd_addr)> body{
+ [](const RawAddress& /* bd_addr */) { return 24; }};
+ uint16_t operator()(const RawAddress& bd_addr) { return body(bd_addr); }
+};
+extern struct L2CA_GetBleConnInterval L2CA_GetBleConnInterval;
// Name: l2cble_notify_le_connection
// Params: const RawAddress& bda
// Returns: void
diff --git a/system/test/mock/mock_stack_l2cap_interface.h b/system/test/mock/mock_stack_l2cap_interface.h
index c87bf164bb..a5cd536777 100644
--- a/system/test/mock/mock_stack_l2cap_interface.h
+++ b/system/test/mock/mock_stack_l2cap_interface.h
@@ -99,6 +99,7 @@ public:
MOCK_METHOD(void, L2CA_LockBleConnParamsForProfileConnection,
(const RawAddress& bd_addr, bool lock));
MOCK_METHOD(tHCI_ROLE, L2CA_GetBleConnRole, (const RawAddress& bd_addr));
+ MOCK_METHOD(uint16_t, L2CA_GetBleConnInterval, (const RawAddress& bd_addr));
MOCK_METHOD(bool, L2CA_SetLeGattTimeout, (const RawAddress& bd_addr, uint16_t idle_tout));
MOCK_METHOD(bool, L2CA_MarkLeLinkAsActive, (const RawAddress& bd_addr));
MOCK_METHOD(bool, L2CA_GetPeerLECocConfig, (uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg));
@@ -106,6 +107,8 @@ public:
MOCK_METHOD(uint16_t, L2CA_LeCreditThreshold, ());
MOCK_METHOD(void, L2CA_Consolidate, (const RawAddress& identity_addr, const RawAddress& rpa));
+ MOCK_METHOD(bool, L2CA_GetAclHandle, (uint16_t lcid, uint16_t* acl_handle));
+ MOCK_METHOD(bool, L2CA_GetLocalMtu, (uint16_t lcid, uint16_t* local_mtu));
// Disconnect methods an active connection for both BR/EDR and BLE
MOCK_METHOD(bool, L2CA_DisconnectReq, (uint16_t cid));
diff --git a/system/test/mock/mock_stack_metrics_logging.cc b/system/test/mock/mock_stack_metrics_logging.cc
index 76ddee2e0b..f2336668e1 100644
--- a/system/test/mock/mock_stack_metrics_logging.cc
+++ b/system/test/mock/mock_stack_metrics_logging.cc
@@ -52,6 +52,9 @@ struct log_manufacturer_info log_manufacturer_info;
struct log_counter_metrics log_counter_metrics;
struct log_hfp_audio_packet_loss_stats log_hfp_audio_packet_loss_stats;
struct log_mmc_transcode_rtt_stats log_mmc_transcode_rtt_stats;
+struct log_le_connection_status log_le_connection_status;
+struct log_le_device_in_accept_list log_le_device_in_accept_list;
+struct log_le_connection_lifecycle log_le_connection_lifecycle;
} // namespace stack_metrics_logging
} // namespace mock
@@ -133,4 +136,20 @@ void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, int num_reque
test::mock::stack_metrics_logging::log_mmc_transcode_rtt_stats(maximum_rtt, mean_rtt,
num_requests, codec_type);
}
+
+void log_le_connection_status(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason) {
+ inc_func_call_count(__func__);
+ test::mock::stack_metrics_logging::log_le_connection_status(address, is_connect, reason);
+}
+
+void log_le_device_in_accept_list(bluetooth::hci::Address address, bool is_add) {
+ inc_func_call_count(__func__);
+ test::mock::stack_metrics_logging::log_le_device_in_accept_list(address, is_add);
+}
+
+void log_le_connection_lifecycle(bluetooth::hci::Address address, bool is_connect, bool is_direct) {
+ inc_func_call_count(__func__);
+ test::mock::stack_metrics_logging::log_le_connection_lifecycle(address, is_connect, is_direct);
+}
// END mockcify generation
diff --git a/system/test/mock/mock_stack_metrics_logging.h b/system/test/mock/mock_stack_metrics_logging.h
index beb3650056..413cbea629 100644
--- a/system/test/mock/mock_stack_metrics_logging.h
+++ b/system/test/mock/mock_stack_metrics_logging.h
@@ -27,6 +27,8 @@
#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
+#include "hci/address.h"
+#include "hci/hci_packets.h"
#include "types/raw_address.h"
// Mocked compile conditionals, if any
@@ -199,6 +201,39 @@ struct log_mmc_transcode_rtt_stats {
}
};
extern struct log_mmc_transcode_rtt_stats log_mmc_transcode_rtt_stats;
+
+// Name: log_le_connection_status
+struct log_le_connection_status {
+ std::function<void(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason)>
+ body{[](bluetooth::hci::Address /* address */, bool /* is_connect */,
+ bluetooth::hci::ErrorCode /* reason */) {}};
+ void operator()(bluetooth::hci::Address address, bool is_connect,
+ bluetooth::hci::ErrorCode reason) {
+ body(address, is_connect, reason);
+ }
+};
+extern struct log_le_connection_status log_le_connection_status;
+
+// Name: log_le_device_in_accept_list
+struct log_le_device_in_accept_list {
+ std::function<void(bluetooth::hci::Address address, bool is_add)> body{
+ [](bluetooth::hci::Address /* address */, bool /* is_add */) {}};
+ void operator()(bluetooth::hci::Address address, bool is_add) { body(address, is_add); }
+};
+extern struct log_le_device_in_accept_list log_le_device_in_accept_list;
+
+// Name: log_le_connection_lifecycle
+struct log_le_connection_lifecycle {
+ std::function<void(bluetooth::hci::Address address, bool is_connect, bool is_direct)> body{
+ [](bluetooth::hci::Address /* address */, bool /* is_connect */, bool /* is_direct */) {
+ }};
+ void operator()(bluetooth::hci::Address address, bool is_connect, bool is_direct) {
+ body(address, is_connect, is_direct);
+ }
+};
+extern struct log_le_device_in_accept_list log_le_device_in_accept_list;
+
} // namespace stack_metrics_logging
} // namespace mock
} // namespace test
diff --git a/system/test/mock/mock_stack_rfcomm_port_api.cc b/system/test/mock/mock_stack_rfcomm_port_api.cc
index e3dffbbf48..b87a752689 100644
--- a/system/test/mock/mock_stack_rfcomm_port_api.cc
+++ b/system/test/mock/mock_stack_rfcomm_port_api.cc
@@ -78,7 +78,7 @@ int RFCOMM_CreateConnectionWithSecurity(uint16_t /* uuid */, uint8_t /* scn */,
bool /* is_server */, uint16_t /* mtu */,
const RawAddress& /* bd_addr */, uint16_t* /* p_handle */,
tPORT_MGMT_CALLBACK* /* p_mgmt_callback */,
- uint16_t /* sec_mask */) {
+ uint16_t /* sec_mask */, RfcommCfgInfo /* cfg */) {
inc_func_call_count(__func__);
return 0;
}
@@ -101,6 +101,15 @@ int PORT_GetSecurityMask(uint16_t /* handle */, uint16_t* /* sec_mask */) {
inc_func_call_count(__func__);
return 0;
}
+int PORT_GetChannelInfo(uint16_t /* handle */, uint16_t* /* local_mtu */,
+ uint16_t* /* remote_mtu */, uint16_t* /* local_credit */,
+ uint16_t* /* remote_credit */, uint16_t* /* local_cid */,
+ uint16_t* /* remote_cid */, uint16_t* /* dlci */,
+ uint16_t* /* max_frame_size */, uint16_t* /* acl_handle */,
+ bool* /* mux_initiator */) {
+ inc_func_call_count(__func__);
+ return 0;
+}
void RFCOMM_Init(void) { inc_func_call_count(__func__); }
bool PORT_IsCollisionDetected(RawAddress /* bd_addr */) {
inc_func_call_count(__func__);
diff --git a/system/test/mock/mock_stack_smp_api.cc b/system/test/mock/mock_stack_smp_api.cc
index 9540022e93..e637bbf3ac 100644
--- a/system/test/mock/mock_stack_smp_api.cc
+++ b/system/test/mock/mock_stack_smp_api.cc
@@ -69,3 +69,8 @@ void SMP_ClearLocScOobData() { inc_func_call_count(__func__); }
void SMP_SirkConfirmDeviceReply(const RawAddress& /* bd_addr */, uint8_t /* res */) {
inc_func_call_count(__func__);
}
+
+uint16_t SMP_GetPendingPairingKeySize() {
+ inc_func_call_count(__func__);
+ return 0;
+} \ No newline at end of file
diff --git a/system/test/mock/mock_stack_srvc_dis.cc b/system/test/mock/mock_stack_srvc_dis.cc
index fc301ea0a1..9a7a3ac884 100644
--- a/system/test/mock/mock_stack_srvc_dis.cc
+++ b/system/test/mock/mock_stack_srvc_dis.cc
@@ -22,22 +22,16 @@
#include <cstdint>
#include "stack/include/srvc_api.h"
+#include "stack/srvc/srvc_dis_int.h"
#include "stack/srvc/srvc_eng_int.h"
#include "test/common/mock_functions.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
bool DIS_ReadDISInfo(const RawAddress& /* peer_bda */, tDIS_READ_CBACK* /* p_cback */,
tDIS_ATTR_MASK /* mask */) {
inc_func_call_count(__func__);
return false;
}
-bool dis_gatt_c_read_dis_req(uint16_t /* conn_id */) {
- inc_func_call_count(__func__);
- return false;
-}
void dis_c_cmpl_cback(tSRVC_CLCB* /* p_clcb */, tGATTC_OPTYPE /* op */, tGATT_STATUS /* status */,
tGATT_CL_COMPLETE* /* p_data */) {
inc_func_call_count(__func__);
diff --git a/system/test/suite/Android.bp b/system/test/suite/Android.bp
index 98307ada71..ac4a5e3b24 100644
--- a/system/test/suite/Android.bp
+++ b/system/test/suite/Android.bp
@@ -65,7 +65,6 @@ cc_defaults {
"lib-bt-packets-avrcp",
"lib-bt-packets-base",
"libFraunhoferAAC",
- "libbluetooth-dumpsys",
"libbluetooth-types",
"libbluetooth_core_rs",
"libbluetooth_core_rs_bridge",
@@ -142,9 +141,6 @@ cc_test {
"libbinder",
"server_configurable_flags",
],
- generated_headers: [
- "BluetoothGeneratedDumpsysDataSchema_h",
- ],
target: {
android: {
static_libs: [
diff --git a/system/test/suite/gatt/gatt_test.cc b/system/test/suite/gatt/gatt_test.cc
index b99dbf77f8..b992d2eab8 100644
--- a/system/test/suite/gatt/gatt_test.cc
+++ b/system/test/suite/gatt/gatt_test.cc
@@ -32,14 +32,6 @@ void RegisterClientCallback(int status, int clientIf, const bluetooth::Uuid& /*a
semaphore_post(instance->register_client_callback_sem_);
}
-void ScanResultCallback(uint16_t /*ble_evt_type*/, uint8_t /*addr_type*/, RawAddress* /*bda*/,
- uint8_t /*ble_primary_phy*/, uint8_t /*ble_secondary_phy*/,
- uint8_t /*ble_advertising_sid*/, int8_t /*ble_tx_power*/, int8_t /*rssi*/,
- uint16_t /*ble_periodic_adv_int*/, std::vector<uint8_t> /*adv_data*/,
- RawAddress* /*original_bda*/) {
- semaphore_post(instance->scan_result_callback_sem_);
-}
-
// GATT server callbacks
void RegisterServerCallback(int status, int server_if, const bluetooth::Uuid& /*uuid*/) {
instance->status_ = status;
@@ -69,10 +61,6 @@ void ServiceDeletedCallback(int status, int server_if, int srvc_handle) {
semaphore_post(instance->service_deleted_callback_sem_);
}
-static const btgatt_scanner_callbacks_t scanner_callbacks = {
- .scan_result_cb = ScanResultCallback,
-};
-
static const btgatt_client_callbacks_t client_callbacks = {
.register_client_cb = RegisterClientCallback,
};
@@ -88,7 +76,6 @@ static const btgatt_callbacks_t callbacks = {
sizeof(btgatt_callbacks_t),
&client_callbacks,
&server_callbacks,
- &scanner_callbacks,
};
void GattTest::SetUp() {
diff --git a/system/test/suite/gatt/gatt_test.h b/system/test/suite/gatt/gatt_test.h
index 6385e6637d..85c2d34ee3 100644
--- a/system/test/suite/gatt/gatt_test.h
+++ b/system/test/suite/gatt/gatt_test.h
@@ -73,7 +73,6 @@ protected:
// Semaphores used to wait for specific callback execution. Each callback
// has its own semaphore associated with it
btsemaphore register_client_callback_sem_;
- btsemaphore scan_result_callback_sem_;
btsemaphore listen_callback_sem_;
btsemaphore register_server_callback_sem_;
diff --git a/system/types/Android.bp b/system/types/Android.bp
index 4201bafca4..00a0de546d 100644
--- a/system/types/Android.bp
+++ b/system/types/Android.bp
@@ -10,7 +10,6 @@ package {
cc_library_headers {
name: "libbluetooth-types-header",
- visibility: ["//visibility:public"],
export_include_dirs: ["./"],
vendor_available: true,
host_supported: true,
@@ -37,7 +36,6 @@ cc_library_static {
/* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
"-fvisibility=default",
],
- visibility: ["//visibility:public"],
host_supported: true,
srcs: [
"bluetooth/uuid.cc",
diff --git a/system/types/remote_version_type.h b/system/types/remote_version_type.h
index 307a9ef102..0c6cab3b86 100644
--- a/system/types/remote_version_type.h
+++ b/system/types/remote_version_type.h
@@ -18,8 +18,6 @@
#pragma once
-#include <base/strings/stringprintf.h>
-
#include <cstdint>
#include <string>
@@ -29,8 +27,7 @@ struct tREMOTE_VERSION_INFO {
uint16_t manufacturer{0};
bool valid{false};
std::string ToString() const {
- return (valid) ? base::StringPrintf("%02hhu-%05hu-%05hu", lmp_version, lmp_subversion,
- manufacturer)
+ return (valid) ? std::format("{:02}-{:05}-{:05}", lmp_version, lmp_subversion, manufacturer)
: std::string("UNKNOWN");
}
};