diff options
419 files changed, 5264 insertions, 6086 deletions
diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000..df0d649f1f --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,4 @@ +--- +CheckOptions: + - key: misc-include-cleaner.IgnoreHeaders + value: (fmt/.*|bits/pthread_types\.h) diff --git a/Android.bp b/Android.bp index 9fbf29d0df..71d6d402c2 100644 --- a/Android.bp +++ b/Android.bp @@ -75,6 +75,27 @@ cc_defaults { cpp_std: "c++20", } +// List of tidy checks that are enabled for cc targets. +// Note that the goal is not to enable all checks, many of them will +// appear as noise especially in the modernize-* range. +bluetooth_tidy_checks = [ + "-*", + "misc-*", + + // This check implements detection of local variables which could be declared + // as const but are not. + "-misc-const-correctness", +] + +// This default tidy checks that will be run against all the cc targets +// developed by the Bluetooth team. +cc_defaults { + name: "bluetooth_tidy", + tidy: true, + tidy_checks: bluetooth_tidy_checks, + tidy_checks_as_errors: bluetooth_tidy_checks, +} + java_defaults { name: "bluetooth_errorprone_rules", errorprone: { @@ -91,6 +112,7 @@ java_defaults { "-Xep:DirectInvocationOnMock:ERROR", "-Xep:EmptyBlockTag:ERROR", "-Xep:EmptyCatch:ERROR", + "-Xep:EnumOrdinal:ERROR", "-Xep:EqualsGetClass:ERROR", "-Xep:EqualsHashCode:ERROR", "-Xep:EqualsIncompatibleType:ERROR", @@ -121,6 +143,8 @@ java_defaults { "-Xep:NonAtomicVolatileUpdate:ERROR", "-Xep:NonCanonicalType:ERROR", "-Xep:NotJavadoc:ERROR", + "-Xep:NullablePrimitive:ERROR", + "-Xep:NullableVoid:ERROR", "-Xep:ObjectEqualsForPrimitives:ERROR", "-Xep:OperatorPrecedence:ERROR", "-Xep:ReferenceEquality:ERROR", @@ -147,8 +171,10 @@ java_defaults { // Exclude generated files "-XepExcludedPaths:.*/srcjars/.*", - // The @InlineMe annotation is not available - // "-Xep:InlineMeSuggester:OFF", + // The @InlineMe annotation could be made available, but it would + // apply on external facing API. This is not desired. For more + // context, see https://r.android.com/3303475 + "-Xep:InlineMeSuggester:OFF", ], }, } diff --git a/TEST_MAPPING b/TEST_MAPPING index 5f21a9b800..5da35c4dc0 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -56,7 +56,7 @@ "name": "net_test_device_iot_config" }, { - "name": "net_test_gatt_conn_multiplexing" + "name": "net_test_conn_multiplexing" }, { "name": "net_test_hci" @@ -108,9 +108,6 @@ "name": "bluetooth_test_common" }, { - "name": "bluetooth_test_sdp" - }, - { "name": "bluetooth_vc_test" }, { @@ -251,7 +248,7 @@ "name": "net_test_device_iot_config" }, { - "name": "net_test_gatt_conn_multiplexing" + "name": "net_test_conn_multiplexing" }, { "name": "net_test_stack" @@ -273,9 +270,6 @@ "name": "bluetooth_test_common" }, { - "name": "bluetooth_test_sdp" - }, - { "name": "bluetooth_vc_test" }, { @@ -320,6 +314,9 @@ "name": "net_test_bta_jv" }, { + "name": "net_test_stack_avctp" + }, + { "name": "asrc_resampler_test" } ] diff --git a/android/app/AndroidManifest.xml b/android/app/AndroidManifest.xml index c77602c8a7..3416c8ff7f 100644 --- a/android/app/AndroidManifest.xml +++ b/android/app/AndroidManifest.xml @@ -203,7 +203,7 @@ </receiver> <activity android:name="com.android.bluetooth.opp.BluetoothOppLauncherActivity" android:process="@string/process" - android:theme="@android:style/Theme.Material.Light.Dialog" + android:theme="@android:style/Theme.Translucent.NoTitleBar" android:label="@string/bt_share_picker_label" android:enabled="false" android:exported="true"> diff --git a/android/app/jni/com_android_bluetooth_BluetoothQualityReport.cpp b/android/app/jni/com_android_bluetooth_BluetoothQualityReport.cpp index d1d48e93b7..b59bc9116f 100644 --- a/android/app/jni/com_android_bluetooth_BluetoothQualityReport.cpp +++ b/android/app/jni/com_android_bluetooth_BluetoothQualityReport.cpp @@ -16,14 +16,21 @@ #define LOG_TAG "BluetoothQualityReportJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/scoped_local_ref.h> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> +#include <vector> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_bqr.h" +#include "types/raw_address.h" -using bluetooth::bqr::BluetoothQualityReportCallbacks; using bluetooth::bqr::BluetoothQualityReportInterface; namespace android { diff --git a/android/app/jni/com_android_bluetooth_a2dp.cpp b/android/app/jni/com_android_bluetooth_a2dp.cpp index f8a6f5480a..2d6e255d15 100644 --- a/android/app/jni/com_android_bluetooth_a2dp.cpp +++ b/android/app/jni/com_android_bluetooth_a2dp.cpp @@ -16,13 +16,24 @@ #define LOG_TAG "bluetooth-a2dp" +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> #include <cstring> +#include <mutex> #include <shared_mutex> +#include <vector> #include "btif/include/btif_av.h" #include "btif/include/btif_util.h" #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_av.h" +#include "types/raw_address.h" namespace android { static jmethodID method_onConnectionStateChanged; diff --git a/android/app/jni/com_android_bluetooth_a2dp_sink.cpp b/android/app/jni/com_android_bluetooth_a2dp_sink.cpp index 44f1fee6cc..f2347e9749 100644 --- a/android/app/jni/com_android_bluetooth_a2dp_sink.cpp +++ b/android/app/jni/com_android_bluetooth_a2dp_sink.cpp @@ -17,14 +17,21 @@ #define LOG_TAG "BluetoothA2dpSinkServiceJni" #include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> +#include <cerrno> +#include <cstdint> #include <cstring> #include <mutex> #include <shared_mutex> #include "btif/include/btif_av.h" #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_av.h" +#include "types/raw_address.h" namespace android { static jmethodID method_onConnectionStateChanged; diff --git a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp index 0d29848e81..a0b80f7902 100644 --- a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp +++ b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp @@ -16,12 +16,21 @@ #define LOG_TAG "BluetoothAvrcpControllerJni" -#include <string.h> - +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_rc.h" +#include "types/raw_address.h" namespace android { static jmethodID method_onConnectionStateChanged; diff --git a/android/app/jni/com_android_bluetooth_avrcp_target.cpp b/android/app/jni/com_android_bluetooth_avrcp_target.cpp index 22f11e4345..9ed217aa2a 100644 --- a/android/app/jni/com_android_bluetooth_avrcp_target.cpp +++ b/android/app/jni/com_android_bluetooth_avrcp_target.cpp @@ -18,14 +18,24 @@ #include <base/functional/bind.h> #include <base/functional/callback.h> -#include <include/hardware/avrcp/avrcp.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <cerrno> +#include <cstdint> +#include <cstring> #include <map> #include <mutex> #include <shared_mutex> +#include <string> +#include <utility> #include <vector> -#include "./com_android_bluetooth.h" +#include "com_android_bluetooth.h" +#include "hardware/avrcp/avrcp.h" +#include "hardware/avrcp/avrcp_common.h" +#include "hardware/bluetooth.h" +#include "types/raw_address.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp index 050fc7b1a5..8e2f4e201d 100644 --- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp @@ -17,21 +17,31 @@ #define LOG_TAG "BluetoothServiceJni" -#include <dlfcn.h> -#include <errno.h> -#include <fcntl.h> -#include <hardware/bluetooth.h> +#include <android/log.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> #include <nativehelper/JNIPlatformHelp.h> +#include <nativehelper/scoped_local_ref.h> #include <pthread.h> -#include <string.h> #include <sys/prctl.h> -#include <sys/stat.h> +#include <array> +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> +#include <string> +#include <utility> +#include <vector> -#include "./com_android_bluetooth.h" +#include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_sock.h" +#include "types/bluetooth/uuid.h" #include "types/bt_transport.h" +#include "types/raw_address.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp b/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp index 330b55703e..5151bbff2f 100644 --- a/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp +++ b/android/app/jni/com_android_bluetooth_btservice_BluetoothKeystore.cpp @@ -16,14 +16,18 @@ #define LOG_TAG "BluetoothKeystoreServiceJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <cstring> +#include <mutex> #include <shared_mutex> +#include <string> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_keystore.h" -using bluetooth::bluetooth_keystore::BluetoothKeystoreCallbacks; using bluetooth::bluetooth_keystore::BluetoothKeystoreInterface; namespace android { diff --git a/android/app/jni/com_android_bluetooth_csip_set_coordinator.cpp b/android/app/jni/com_android_bluetooth_csip_set_coordinator.cpp index f083457386..0f30fb11ba 100644 --- a/android/app/jni/com_android_bluetooth_csip_set_coordinator.cpp +++ b/android/app/jni/com_android_bluetooth_csip_set_coordinator.cpp @@ -15,14 +15,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #define LOG_TAG "BluetoothCsipSetCoordinatorJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_csis.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" +using bluetooth::Uuid; using bluetooth::csis::ConnectionState; using bluetooth::csis::CsisClientCallbacks; using bluetooth::csis::CsisClientInterface; @@ -40,8 +53,6 @@ static std::shared_timed_mutex interface_mutex; static jobject mCallbacksObj = nullptr; static std::shared_timed_mutex callbacks_mutex; -using bluetooth::Uuid; - #define UUID_PARAMS(uuid) uuid_lsb(uuid), uuid_msb(uuid) static uint64_t uuid_lsb(const Uuid& uuid) { diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp index 0264da919f..9bde897040 100644 --- a/android/app/jni/com_android_bluetooth_gatt.cpp +++ b/android/app/jni/com_android_bluetooth_gatt.cpp @@ -18,20 +18,40 @@ #include <base/functional/bind.h> #include <base/functional/callback.h> -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> #include <array> +#include <cerrno> +#include <cstdint> +#include <cstdio> +#include <cstring> +#include <functional> #include <memory> +#include <mutex> #include <shared_mutex> +#include <string> +#include <utility> +#include <vector> #include "com_android_bluetooth.h" #include "com_android_bluetooth_flags.h" +#include "hardware/ble_advertiser.h" +#include "hardware/ble_scanner.h" +#include "hardware/bluetooth.h" +#include "hardware/bt_common_types.h" #include "hardware/bt_gatt.h" +#include "hardware/bt_gatt_client.h" +#include "hardware/bt_gatt_server.h" #include "hardware/bt_gatt_types.h" +#include "hardware/distance_measurement_interface.h" #include "main/shim/le_scanning_manager.h" #include "rust/cxx.h" -#include "rust/src/gatt/ffi/gatt_shim.h" #include "src/gatt/ffi.rs.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/android/app/jni/com_android_bluetooth_hap_client.cpp b/android/app/jni/com_android_bluetooth_hap_client.cpp index 295a207a4c..d2bdcbac8d 100644 --- a/android/app/jni/com_android_bluetooth_hap_client.cpp +++ b/android/app/jni/com_android_bluetooth_hap_client.cpp @@ -17,12 +17,24 @@ #define LOG_TAG "BluetoothHapClientJni" -#include <string.h> - +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> +#include <utility> +#include <variant> +#include <vector> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_has.h" +#include "types/raw_address.h" using bluetooth::has::ConnectionState; using bluetooth::has::ErrorCode; diff --git a/android/app/jni/com_android_bluetooth_hearing_aid.cpp b/android/app/jni/com_android_bluetooth_hearing_aid.cpp index edf8dc5865..dbe2439ed4 100644 --- a/android/app/jni/com_android_bluetooth_hearing_aid.cpp +++ b/android/app/jni/com_android_bluetooth_hearing_aid.cpp @@ -16,12 +16,21 @@ #define LOG_TAG "BluetoothHearingAidServiceJni" -#include <string.h> - +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_hearing_aid.h" +#include "types/raw_address.h" using bluetooth::hearing_aid::ConnectionState; using bluetooth::hearing_aid::HearingAidCallbacks; diff --git a/android/app/jni/com_android_bluetooth_hfp.cpp b/android/app/jni/com_android_bluetooth_hfp.cpp index c1d982de17..0a53d42c6f 100644 --- a/android/app/jni/com_android_bluetooth_hfp.cpp +++ b/android/app/jni/com_android_bluetooth_hfp.cpp @@ -17,15 +17,22 @@ #define LOG_TAG "BluetoothHeadsetServiceJni" #include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> +#include <cerrno> +#include <cstdint> +#include <cstring> #include <mutex> #include <shared_mutex> -#include "btif/include/btif_hf.h" #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bluetooth_headset_callbacks.h" #include "hardware/bluetooth_headset_interface.h" #include "hardware/bt_hf.h" +#include "types/raw_address.h" namespace android { diff --git a/android/app/jni/com_android_bluetooth_hfpclient.cpp b/android/app/jni/com_android_bluetooth_hfpclient.cpp index f42d8dd210..daf575204e 100644 --- a/android/app/jni/com_android_bluetooth_hfpclient.cpp +++ b/android/app/jni/com_android_bluetooth_hfpclient.cpp @@ -17,11 +17,20 @@ #define LOG_TAG "BluetoothHeadsetClientServiceJni" +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstring> +#include <mutex> #include <shared_mutex> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_hf_client.h" -#include "os/logging/log_adapter.h" +#include "types/raw_address.h" namespace android { diff --git a/android/app/jni/com_android_bluetooth_hid_device.cpp b/android/app/jni/com_android_bluetooth_hid_device.cpp index 6ff86e0530..5f2b98a2ce 100644 --- a/android/app/jni/com_android_bluetooth_hid_device.cpp +++ b/android/app/jni/com_android_bluetooth_hid_device.cpp @@ -16,10 +16,18 @@ #define LOG_TAG "BluetoothHidDeviceServiceJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cstdint> +#include <cstdlib> +#include <cstring> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_hd.h" +#include "types/raw_address.h" namespace android { diff --git a/android/app/jni/com_android_bluetooth_hid_host.cpp b/android/app/jni/com_android_bluetooth_hid_host.cpp index fcd28e5bbc..267eea8f84 100644 --- a/android/app/jni/com_android_bluetooth_hid_host.cpp +++ b/android/app/jni/com_android_bluetooth_hid_host.cpp @@ -16,13 +16,23 @@ #define LOG_TAG "BluetoothHidHostServiceJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/scoped_local_ref.h> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_hh.h" +#include "types/ble_address_with_type.h" +#include "types/bt_transport.h" +#include "types/raw_address.h" #include "utils/Log.h" + namespace android { static jmethodID method_onConnectStateChanged; diff --git a/android/app/jni/com_android_bluetooth_le_audio.cpp b/android/app/jni/com_android_bluetooth_le_audio.cpp index 69c25d99b3..4ce436e5c4 100644 --- a/android/app/jni/com_android_bluetooth_le_audio.cpp +++ b/android/app/jni/com_android_bluetooth_le_audio.cpp @@ -16,14 +16,29 @@ #define LOG_TAG "BluetoothLeAudioServiceJni" -#include <hardware/bluetooth.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> +#include <algorithm> #include <array> +#include <cctype> +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <map> +#include <mutex> #include <optional> #include <shared_mutex> +#include <string> +#include <type_traits> +#include <vector> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_le_audio.h" +#include "types/raw_address.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/android/app/jni/com_android_bluetooth_pan.cpp b/android/app/jni/com_android_bluetooth_pan.cpp index 195b8fefc2..f0c78eac72 100644 --- a/android/app/jni/com_android_bluetooth_pan.cpp +++ b/android/app/jni/com_android_bluetooth_pan.cpp @@ -16,10 +16,16 @@ #define LOG_TAG "BluetoothPanServiceJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cstring> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_pan.h" +#include "types/raw_address.h" namespace android { diff --git a/android/app/jni/com_android_bluetooth_sdp.cpp b/android/app/jni/com_android_bluetooth_sdp.cpp index 1d49fca11a..e667dbcd8c 100644 --- a/android/app/jni/com_android_bluetooth_sdp.cpp +++ b/android/app/jni/com_android_bluetooth_sdp.cpp @@ -16,10 +16,20 @@ #define LOG_TAG "BluetoothSdpJni" -#include <string.h> +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> +#include <cstring> #include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_sdp.h" +#include "types/bluetooth/uuid.h" +#include "types/raw_address.h" using bluetooth::Uuid; diff --git a/android/app/jni/com_android_bluetooth_vc.cpp b/android/app/jni/com_android_bluetooth_vc.cpp index c998c0f7a1..39bd355dad 100644 --- a/android/app/jni/com_android_bluetooth_vc.cpp +++ b/android/app/jni/com_android_bluetooth_vc.cpp @@ -17,12 +17,22 @@ #define LOG_TAG "BluetoothVolumeControlServiceJni" -#include <string.h> - +#include <bluetooth/log.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/scoped_local_ref.h> + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <mutex> #include <shared_mutex> +#include <string> -#include "./com_android_bluetooth.h" +#include "com_android_bluetooth.h" +#include "hardware/bluetooth.h" #include "hardware/bt_vc.h" +#include "types/raw_address.h" using bluetooth::vc::ConnectionState; using bluetooth::vc::VolumeControlCallbacks; 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 737cdb541c..7a0389ad2c 100644 --- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java @@ -124,6 +124,7 @@ public class BassClientService extends ProfileService { @VisibleForTesting static final int MESSAGE_SYNC_TIMEOUT = 1; @VisibleForTesting static final int MESSAGE_BIG_MONITOR_TIMEOUT = 2; @VisibleForTesting static final int MESSAGE_BROADCAST_MONITOR_TIMEOUT = 3; + @VisibleForTesting static final int MESSAGE_SYNC_LOST_TIMEOUT = 4; /* 1 minute timeout for primary device reconnection in Private Broadcast case */ private static final int DIALING_OUT_TIMEOUT_MS = 60000; @@ -137,6 +138,9 @@ public class BassClientService extends ProfileService { // 5 minutes timeout for monitoring broadcaster private static final Duration sBroadcasterMonitorTimeout = Duration.ofMinutes(5); + // 5 seconds timeout for sync Lost notification + private static final Duration sSyncLostTimeout = Duration.ofSeconds(5); + private enum PauseType { HOST_INTENTIONAL, SINK_UNINTENTIONAL @@ -165,6 +169,8 @@ public class BassClientService extends ProfileService { private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = new ConcurrentHashMap<>(); private final HashSet<BluetoothDevice> mPausedBroadcastSinks = new HashSet<>(); + private final Map<BluetoothDevice, Pair<Integer, Integer>> mSinksWaitingForPast = + new HashMap<>(); private final Map<Integer, PauseType> mPausedBroadcastIds = new HashMap<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers = @@ -216,39 +222,124 @@ public class BassClientService extends ProfileService { clearAllSyncData(); break; } - case MESSAGE_BROADCAST_MONITOR_TIMEOUT: - { - log("MESSAGE_BROADCAST_MONITOR_TIMEOUT"); - int broadcastId = msg.arg1; - List<Integer> activeSyncedSrc = - new ArrayList<>(getActiveSyncedSources()); - if (activeSyncedSrc.contains( - getSyncHandleForBroadcastId(broadcastId))) { - break; - } - log("Notify broadcast source lost, broadcast id: " + broadcastId); - mCallbacks.notifySourceLost(broadcastId); - // fall through - } - case MESSAGE_BIG_MONITOR_TIMEOUT: - { - log("MESSAGE_BIG_MONITOR_TIMEOUT"); - int broadcastId = msg.arg1; - stopSourceReceivers(broadcastId); - synchronized (mSearchScanCallbackLock) { - // when searching is stopped then clear all sync data - if (mSearchScanCallback == null) { - clearAllSyncData(); - } - } - break; - } default: break; } } }; + @VisibleForTesting public final TimeoutHandler mTimeoutHandler = new TimeoutHandler(); + + @VisibleForTesting + public final class TimeoutHandler { + private final Map<Integer, Handler> mHandlers = new HashMap<>(); + + @VisibleForTesting + public Handler getOrCreateHandler(int broadcastId) { + return mHandlers.computeIfAbsent( + broadcastId, + key -> + new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_SYNC_LOST_TIMEOUT: + { + log("MESSAGE_SYNC_LOST_TIMEOUT"); + // fall through + } + case MESSAGE_BROADCAST_MONITOR_TIMEOUT: + { + log("MESSAGE_BROADCAST_MONITOR_TIMEOUT"); + List<Integer> activeSyncedSrc = + new ArrayList<>(getActiveSyncedSources()); + if (activeSyncedSrc.contains( + getSyncHandleForBroadcastId(broadcastId))) { + break; + } + // Clear from cache to make possible sync again + // (only during active searching) + synchronized (mSearchScanCallbackLock) { + if (mSearchScanCallback != null) { + mCachedBroadcasts.remove(broadcastId); + } + } + log( + "Notify broadcast source lost, broadcast" + + " id: " + + broadcastId); + mCallbacks.notifySourceLost(broadcastId); + if (!isSinkUnintentionalPauseType(broadcastId)) { + break; + } + // fall through + } + case MESSAGE_BIG_MONITOR_TIMEOUT: + { + log("MESSAGE_BIG_MONITOR_TIMEOUT"); + stopSourceReceivers(broadcastId); + break; + } + default: + break; + } + Handler handler = getOrCreateHandler(broadcastId); + if (!handler.hasMessagesOrCallbacks()) { + mHandlers.remove(broadcastId); + } + } + }); + } + + void start(int broadcastId, int msg, Duration duration) { + Handler handler = getOrCreateHandler(broadcastId); + log( + "Started timeout: " + + ("broadcastId: " + broadcastId) + + (", msg: " + msg) + + (", duration: " + duration)); + handler.sendEmptyMessageDelayed(msg, duration.toMillis()); + } + + void stop(int broadcastId, int msg) { + if (!mHandlers.containsKey(broadcastId)) { + return; + } + Handler handler = getOrCreateHandler(broadcastId); + handler.removeMessages(msg); + if (!handler.hasMessagesOrCallbacks()) { + mHandlers.remove(broadcastId); + } + } + + void stopAll() { + for (Handler handler : mHandlers.values()) { + handler.removeCallbacksAndMessages(null); + } + mHandlers.clear(); + } + + void stopAll(int msg) { + Iterator<Map.Entry<Integer, Handler>> iterator = mHandlers.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry<Integer, Handler> entry = iterator.next(); + Handler handler = entry.getValue(); + handler.removeMessages(msg); + if (!handler.hasMessagesOrCallbacks()) { + iterator.remove(); + } + } + } + + boolean isStarted(int broadcastId, int msg) { + if (!mHandlers.containsKey(broadcastId)) { + return false; + } + Handler handler = getOrCreateHandler(broadcastId); + return handler.hasMessages(msg); + } + } + public BassClientService(Context ctx) { super(ctx); } @@ -710,6 +801,7 @@ public class BassClientService extends ProfileService { } mHandler.removeCallbacksAndMessages(null); + mTimeoutHandler.stopAll(); setBassClientService(null); if (!leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { @@ -1010,6 +1102,24 @@ public class BassClientService extends ProfileService { } } + void syncRequestForPast(BluetoothDevice sink, int broadcastId, int sourceId) { + log( + "syncRequestForPast sink: " + + sink + + ", broadcastId: " + + broadcastId + + ", sourceId: " + + sourceId); + + if (!leaudioBroadcastResyncHelper()) { + return; + } + synchronized (mSinksWaitingForPast) { + mSinksWaitingForPast.put(sink, new Pair<Integer, Integer>(broadcastId, sourceId)); + } + addSelectSourceRequest(broadcastId, true); + } + private void localNotifyReceiveStateChanged( BluetoothDevice sink, BluetoothLeBroadcastReceiveState receiveState) { int broadcastId = receiveState.getBroadcastId(); @@ -1017,38 +1127,29 @@ public class BassClientService extends ProfileService { && !isLocalBroadcast(receiveState) && !isEmptyBluetoothDevice(receiveState.getSourceDevice()) && !isHostPauseType(broadcastId)) { - boolean isReadyToAutoResync = false; - if (receiveState.getPaSyncState() - == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) { - isReadyToAutoResync = 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) { - isReadyToAutoResync = true; - break; - } - } - } - if (isReadyToAutoResync) { - stopBigMonitoring(broadcastId, false); + if (isReceiverActive(receiveState) + || receiveState.getPaSyncState() + == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCINFO_REQUEST) { + mPausedBroadcastSinks.remove(sink); + if (isAllReceiversActive(broadcastId) && mPausedBroadcastSinks.isEmpty()) { + stopBigMonitoring(broadcastId, false); + } } else if (!mPausedBroadcastIds.containsKey(broadcastId)) { if (mCachedBroadcasts.containsKey(broadcastId)) { addSelectSourceRequest(broadcastId, true); mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNINTENTIONAL); cacheSuspendingSources(broadcastId); - mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); - Message newMsg = mHandler.obtainMessage(MESSAGE_BIG_MONITOR_TIMEOUT); - newMsg.arg1 = broadcastId; - log("Started MESSAGE_BIG_MONITOR_TIMEOUT"); - mHandler.sendMessageDelayed(newMsg, sBigMonitorTimeout.toMillis()); + mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); + mTimeoutHandler.start( + broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT, sBigMonitorTimeout); } } } else if (isEmptyBluetoothDevice(receiveState.getSourceDevice())) { + synchronized (mSinksWaitingForPast) { + mSinksWaitingForPast.remove(sink); + } checkAndStopBigMonitoring(); } @@ -1489,8 +1590,9 @@ public class BassClientService extends ProfileService { if (toState == BluetoothProfile.STATE_DISCONNECTED) { mPendingGroupOp.remove(device); mPausedBroadcastSinks.remove(device); - - checkAndStopBigMonitoring(); + synchronized (mSinksWaitingForPast) { + mSinksWaitingForPast.remove(device); + } int bondState = mAdapterService.getBondState(device); if (bondState == BluetoothDevice.BOND_NONE) { @@ -1498,6 +1600,20 @@ public class BassClientService extends ProfileService { removeStateMachine(device); } + checkAndStopBigMonitoring(); + + if (getConnectedDevices().isEmpty() + || (mPausedBroadcastSinks.isEmpty() + && mSinksWaitingForPast.isEmpty() + && !isAnyConnectedDeviceSwitchingSource())) { + synchronized (mSearchScanCallbackLock) { + // when searching is stopped then clear all sync data + if (mSearchScanCallback == null) { + clearAllSyncData(); + } + } + } + /* Restore allowed context mask for unicast in case if last connected broadcast * delegator device which has external source disconnectes. */ @@ -1832,8 +1948,10 @@ public class BassClientService extends ProfileService { TAG, "Broadcast Source Found: Broadcast ID: " + broadcastId); - if (broadcastId != BassConstants.INVALID_BROADCAST_ID - && !mCachedBroadcasts.containsKey(broadcastId)) { + if (broadcastId == BassConstants.INVALID_BROADCAST_ID) { + return; + } + if (!mCachedBroadcasts.containsKey(broadcastId)) { log("selectBroadcastSource: broadcastId " + broadcastId); mCachedBroadcasts.put(broadcastId, result); if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { @@ -1848,6 +1966,14 @@ public class BassClientService extends ProfileService { } } } + } else if (leaudioBroadcastResyncHelper() + && mTimeoutHandler.isStarted( + broadcastId, MESSAGE_SYNC_LOST_TIMEOUT)) { + mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); + mTimeoutHandler.start( + broadcastId, + MESSAGE_SYNC_LOST_TIMEOUT, + sSyncLostTimeout); } } } @@ -1970,6 +2096,7 @@ public class BassClientService extends ProfileService { private void clearAllSyncData() { log("clearAllSyncData"); + mTimeoutHandler.stopAll(MESSAGE_SYNC_LOST_TIMEOUT); mSourceSyncRequestsQueue.clear(); mSyncFailureCounter.clear(); mPendingSourcesToAdd.clear(); @@ -2047,7 +2174,7 @@ public class BassClientService extends ProfileService { } } } else { - mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); + mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); } // update valid sync handle in mPeriodicAdvCallbacksMap @@ -2061,6 +2188,41 @@ public class BassClientService extends ProfileService { } mBisDiscoveryCounterMap.put(syncHandle, MAX_BIS_DISCOVERY_TRIES_NUM); + synchronized (mSinksWaitingForPast) { + Iterator<Map.Entry<BluetoothDevice, Pair<Integer, Integer>>> iterator = + mSinksWaitingForPast.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry<BluetoothDevice, Pair<Integer, Integer>> entry = iterator.next(); + BluetoothDevice sinkDevice = entry.getKey(); + int broadcastIdForPast = entry.getValue().first; + if (broadcastId == broadcastIdForPast) { + int sourceId = entry.getValue().second; + synchronized (mStateMachines) { + BassClientStateMachine sm = getOrCreateStateMachine(sinkDevice); + Message message = + sm.obtainMessage( + BassClientStateMachine.INITIATE_PA_SYNC_TRANSFER); + message.arg1 = syncHandle; + message.arg2 = sourceId; + sm.sendMessage(message); + } + synchronized (mPendingSourcesToAdd) { + Iterator<AddSourceData> addIterator = + mPendingSourcesToAdd.iterator(); + while (addIterator.hasNext()) { + AddSourceData pendingSourcesToAdd = addIterator.next(); + if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() + == broadcastId + && pendingSourcesToAdd.mSink.equals(sinkDevice)) { + addIterator.remove(); + } + } + } + iterator.remove(); + } + } + } + synchronized (mPendingSourcesToAdd) { Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator(); while (iterator.hasNext()) { @@ -2100,11 +2262,12 @@ public class BassClientService extends ProfileService { mSyncFailureCounter.put(broadcastId, failsCounter); } if (isSinkUnintentionalPauseType(broadcastId)) { - if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { - Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT); - newMsg.arg1 = broadcastId; - log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT"); - mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis()); + if (!mTimeoutHandler.isStarted( + broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { + mTimeoutHandler.start( + broadcastId, + MESSAGE_BROADCAST_MONITOR_TIMEOUT, + sBroadcasterMonitorTimeout); } addSelectSourceRequest(broadcastId, true); } else { @@ -2183,23 +2346,31 @@ public class BassClientService extends ProfileService { int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1; mSyncFailureCounter.put(broadcastId, failsCounter); } + mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); if (isSinkUnintentionalPauseType(broadcastId)) { - if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { - Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT); - newMsg.arg1 = broadcastId; - log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT"); - mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis()); + if (!mTimeoutHandler.isStarted( + broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) { + mTimeoutHandler.start( + broadcastId, + MESSAGE_BROADCAST_MONITOR_TIMEOUT, + sBroadcasterMonitorTimeout); } addSelectSourceRequest(broadcastId, true); } else { - // Clear from cache to make possible sync again (only during active searching) - synchronized (mSearchScanCallbackLock) { - if (mSearchScanCallback != null) { - mCachedBroadcasts.remove(broadcastId); + if (leaudioBroadcastResyncHelper()) { + mTimeoutHandler.start( + broadcastId, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); + } else { + // Clear from cache to make possible sync again (only during active + // searching) + synchronized (mSearchScanCallbackLock) { + if (mSearchScanCallback != null) { + mCachedBroadcasts.remove(broadcastId); + } } + log("Notify broadcast source lost, broadcast id: " + broadcastId); + mCallbacks.notifySourceLost(broadcastId); } - log("Notify broadcast source lost, broadcast id: " + broadcastId); - mCallbacks.notifySourceLost(broadcastId); } } } @@ -2480,7 +2651,7 @@ public class BassClientService extends ProfileService { + broadcastId + ", hasPriority: " + hasPriority); - + mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT); ScanResult scanRes = getCachedBroadcast(broadcastId); if (scanRes != null) { ScanRecord scanRecord = scanRes.getScanRecord(); @@ -2572,9 +2743,11 @@ public class BassClientService extends ProfileService { cancelActiveSync(syncHandle); } else { Boolean canceledActiveSync = false; + int broadcstIdToLostMonitoring = BassConstants.INVALID_BROADCAST_ID; for (int syncHandle : activeSyncedSrc) { if (!isAnyReceiverSyncedToBroadcast(getBroadcastIdForSyncHandle(syncHandle))) { canceledActiveSync = true; + broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle); cancelActiveSync(syncHandle); break; } @@ -2582,8 +2755,11 @@ public class BassClientService extends ProfileService { if (!canceledActiveSync) { int syncHandle = activeSyncedSrc.get(0); // removing the 1st synced source before proceeding to add new + broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle); cancelActiveSync(syncHandle); } + mTimeoutHandler.start( + broadcstIdToLostMonitoring, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout); } } @@ -3447,14 +3623,13 @@ public class BassClientService extends ProfileService { return; } log("stopBigMonitoring"); - mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); - mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); - mPausedBroadcastSinks.clear(); Iterator<Integer> iterator = mPausedBroadcastIds.keySet().iterator(); while (iterator.hasNext()) { int pausedBroadcastId = iterator.next(); + mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); + mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); iterator.remove(); synchronized (mSearchScanCallbackLock) { // when searching is stopped then stop active sync @@ -3475,8 +3650,8 @@ public class BassClientService extends ProfileService { while (iterator.hasNext()) { int pausedBroadcastId = iterator.next(); if (!isAnyReceiverSyncedToBroadcast(pausedBroadcastId)) { - mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); - mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); + mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); + mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); iterator.remove(); synchronized (mSearchScanCallbackLock) { // when searching is stopped then stop active sync @@ -3494,8 +3669,8 @@ public class BassClientService extends ProfileService { return; } log("stopBigMonitoring broadcastId: " + broadcastId + ", hostInitiated: " + hostInitiated); - mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT); - mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT); + mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT); + mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT); if (hostInitiated) { mPausedBroadcastIds.put(broadcastId, PauseType.HOST_INTENTIONAL); } else { @@ -3579,14 +3754,23 @@ public class BassClientService extends ProfileService { .filter(e -> e.getBroadcastId() == metadata.getBroadcastId()) .findAny(); + if (leaudioBroadcastResyncHelper() + && receiveState.isPresent() + && (receiveState.get().getPaSyncState() + == BluetoothLeBroadcastReceiveState + .PA_SYNC_STATE_SYNCINFO_REQUEST + || receiveState.get().getPaSyncState() + == BluetoothLeBroadcastReceiveState + .PA_SYNC_STATE_SYNCHRONIZED)) { + iterator.remove(); + continue; + } + List<Integer> activeSyncedSrc = getActiveSyncedSources(); if (receiveState.isPresent() && (!leaudioBroadcastResyncHelper() || isLocalBroadcast(metadata) - || receiveState.get().getPaSyncState() - == BluetoothLeBroadcastReceiveState - .PA_SYNC_STATE_SYNCHRONIZED || activeSyncedSrc.contains( getSyncHandleForBroadcastId(metadata.getBroadcastId())))) { int sourceId = receiveState.get().getSourceId(); @@ -3743,26 +3927,51 @@ public class BassClientService extends ProfileService { return false; } + private boolean isReceiverActive(BluetoothLeBroadcastReceiveState receiveState) { + if (receiveState.getPaSyncState() + == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) { + 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) { + return true; + } + } + } + return false; + } + private Set<Integer> getExternalBroadcastsActiveOnSinks() { HashSet<Integer> syncedBroadcasts = new HashSet<>(); for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { - if (!isLocalBroadcast(receiveState)) { - 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) { - syncedBroadcasts.add(receiveState.getBroadcastId()); - log("getExternalBroadcastsActiveOnSinks: " + receiveState); - } - } + if (isLocalBroadcast(receiveState)) { + continue; + } + if (isReceiverActive(receiveState)) { + syncedBroadcasts.add(receiveState.getBroadcastId()); + log("getExternalBroadcastsActiveOnSinks: " + receiveState); } } } return syncedBroadcasts; } + private boolean isAllReceiversActive(int broadcastId) { + for (BluetoothDevice device : getConnectedDevices()) { + for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { + if (receiveState.getBroadcastId() == broadcastId + && !isReceiverActive(receiveState)) { + return false; + } + } + } + return true; + } + /** Get sink devices synced to the broadcasts */ public List<BluetoothDevice> getSyncedBroadcastSinks() { List<BluetoothDevice> activeSinks = new ArrayList<>(); 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 adca0a07b6..b59ff2fcd2 100644 --- a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java @@ -84,8 +84,7 @@ import java.util.Scanner; import java.util.UUID; import java.util.stream.IntStream; -@VisibleForTesting -public class BassClientStateMachine extends StateMachine { +class BassClientStateMachine extends StateMachine { private static final String TAG = "BassClientStateMachine"; @VisibleForTesting static final byte[] REMOTE_SCAN_STOP = {00}; @VisibleForTesting static final byte[] REMOTE_SCAN_START = {01}; @@ -113,6 +112,7 @@ public class BassClientStateMachine extends StateMachine { static final int REACHED_MAX_SOURCE_LIMIT = 16; static final int SWITCH_BCAST_SOURCE = 17; static final int CANCEL_PENDING_SOURCE_OPERATION = 18; + static final int INITIATE_PA_SYNC_TRANSFER = 19; // NOTE: the value is not "final" - it is modified in the unit tests @VisibleForTesting private int mConnectTimeoutMs; @@ -816,69 +816,80 @@ public class BassClientStateMachine extends StateMachine { int state = recvState.getPaSyncState(); if (state == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCINFO_REQUEST) { log("Initiate PAST procedure"); - PeriodicAdvertisementResult result = - mService.getPeriodicAdvertisementResult( - recvState.getSourceDevice(), recvState.getBroadcastId()); - if (result != null) { - int syncHandle = result.getSyncHandle(); - log("processPASyncState: syncHandle " + result.getSyncHandle()); - if (syncHandle != BassConstants.INVALID_SYNC_HANDLE) { - serviceData = 0x000000FF & recvState.getSourceId(); - 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); - log( - "Initiate PAST for: " - + mDevice - + ", syncHandle: " - + syncHandle - + "serviceData" - + serviceData); - BluetoothMethodProxy.getInstance() - .periodicAdvertisingManagerTransferSync( - BassClientPeriodicAdvertisingManager - .getPeriodicAdvertisingManager(), - mDevice, - serviceData, - syncHandle); - } + int sourceId = recvState.getSourceId(); + BluetoothLeBroadcastMetadata currentMetadata = getCurrentBroadcastMetadata(sourceId); + if (mService.isLocalBroadcast(currentMetadata)) { + int advHandle = currentMetadata.getSourceAdvertisingSid(); + 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; + log( + "Initiate local broadcast PAST for: " + + mDevice + + ", advSID/Handle: " + + advHandle + + ", serviceData: " + + serviceData); + BluetoothMethodProxy.getInstance() + .periodicAdvertisingManagerTransferSetInfo( + BassClientPeriodicAdvertisingManager + .getPeriodicAdvertisingManager(), + mDevice, + serviceData, + advHandle, + mLocalPeriodicAdvCallback); } else { - BluetoothLeBroadcastMetadata currentMetadata = - getCurrentBroadcastMetadata(recvState.getSourceId()); - if (mService.isLocalBroadcast(currentMetadata)) { - int advHandle = currentMetadata.getSourceAdvertisingSid(); - serviceData = 0x000000FF & recvState.getSourceId(); - 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; - log( - "Initiate local broadcast PAST for: " - + mDevice - + ", advSID/Handle: " - + advHandle - + ", serviceData: " - + serviceData); - BluetoothMethodProxy.getInstance() - .periodicAdvertisingManagerTransferSetInfo( - BassClientPeriodicAdvertisingManager - .getPeriodicAdvertisingManager(), - mDevice, - serviceData, - advHandle, - mLocalPeriodicAdvCallback); - } else { - Log.e(TAG, "There is no valid sync handle for this Source"); + int broadcastId = recvState.getBroadcastId(); + PeriodicAdvertisementResult result = + mService.getPeriodicAdvertisementResult( + recvState.getSourceDevice(), broadcastId); + if (result != null) { + int syncHandle = result.getSyncHandle(); + if (syncHandle != BassConstants.INVALID_SYNC_HANDLE) { + initiatePaSyncTransfer(syncHandle, sourceId); + return; + } } + mService.syncRequestForPast(mDevice, broadcastId, sourceId); } } } + private void initiatePaSyncTransfer(int syncHandle, int sourceId) { + if (syncHandle != BassConstants.INVALID_SYNC_HANDLE + && sourceId != BassConstants.INVALID_SOURCE_ID) { + 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); + log( + "Initiate PAST for: " + + mDevice + + ", syncHandle: " + + syncHandle + + ", serviceData: " + + serviceData); + BluetoothMethodProxy.getInstance() + .periodicAdvertisingManagerTransferSync( + BassClientPeriodicAdvertisingManager.getPeriodicAdvertisingManager(), + mDevice, + serviceData, + syncHandle); + } else { + Log.e( + TAG, + "Invalid syncHandle or sourceId for PAST, syncHandle: " + + syncHandle + + ", sourceId: " + + sourceId); + } + } + private void processSyncStateChangeStats(BluetoothLeBroadcastReceiveState recvState) { int sourceId = recvState.getSourceId(); BluetoothLeBroadcastMetadata metaData = getCurrentBroadcastMetadata(sourceId); @@ -2350,6 +2361,11 @@ public class BassClientStateMachine extends StateMachine { int broadcastId = message.arg1; cancelPendingSourceOperation(broadcastId); break; + case INITIATE_PA_SYNC_TRANSFER: + int syncHandle = message.arg1; + int sourceIdForPast = message.arg2; + initiatePaSyncTransfer(syncHandle, sourceIdForPast); + break; default: log("CONNECTED: not handled message:" + message.what); return NOT_HANDLED; @@ -2539,6 +2555,7 @@ public class BassClientStateMachine extends StateMachine { case REACHED_MAX_SOURCE_LIMIT: case SWITCH_BCAST_SOURCE: case PSYNC_ACTIVE_TIMEOUT: + case INITIATE_PA_SYNC_TRANSFER: log( "defer the message: " + messageWhatToString(message.what) @@ -2646,6 +2663,8 @@ public class BassClientStateMachine extends StateMachine { return "CONNECT_TIMEOUT"; case CANCEL_PENDING_SOURCE_OPERATION: return "CANCEL_PENDING_SOURCE_OPERATION"; + case INITIATE_PA_SYNC_TRANSFER: + return "INITIATE_PA_SYNC_TRANSFER"; default: break; } diff --git a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java index 9b926f1306..8520bc371f 100644 --- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java @@ -1041,6 +1041,23 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac return false; } + @GuardedBy("mLock") + private boolean areSameGroupMembers(BluetoothDevice firstDevice, BluetoothDevice secondDevice) { + + if (!Flags.admFixDisconnectOfSetMember()) { + /* This function shall return false without the fix flag. */ + return false; + } + + final LeAudioService leAudioService = mFactory.getLeAudioService(); + if (leAudioService == null) { + Log.e(TAG, "LeAudioService not available"); + return false; + } + + return leAudioService.getGroupId(firstDevice) == leAudioService.getGroupId(secondDevice); + } + /** * TODO: This method can return true when a fallback device for an unrelated profile is found. * Take disconnected profile as an argument, and find the exact fallback device. Also, split @@ -1083,6 +1100,13 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac setLeAudioActiveDevice(null, hasFallbackDevice); } else { Log.d(TAG, "Found a LE hearing aid fallback device: " + device); + if (areSameGroupMembers(recentlyRemovedDevice, device)) { + Log.d( + TAG, + "Do nothing, removed device belong to the same group as the" + + " fallback device."); + return true; + } setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null, hasFallbackDevice); setA2dpActiveDevice(null, hasFallbackDevice); @@ -1152,6 +1176,14 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac setHearingAidActiveDevice(null, true); } else { Log.d(TAG, "Found a LE audio fallback device: " + device); + if (areSameGroupMembers(recentlyRemovedDevice, device)) { + Log.d( + TAG, + "Do nothing, removed device belong to the same group as the fallback" + + " device."); + return true; + } + if (!setLeAudioActiveDevice(device)) { return false; } @@ -1181,6 +1213,14 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac setHearingAidActiveDevice(null, true); } else { Log.d(TAG, "Found a LE audio fallback device: " + device); + if (areSameGroupMembers(recentlyRemovedDevice, device)) { + Log.d( + TAG, + "Do nothing, removed device belong to the same group as the fallback" + + " device."); + return true; + } + setLeAudioActiveDevice(device); if (!Utils.isDualModeAudioEnabled()) { setA2dpActiveDevice(null, true); diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java index 42191c742c..43752e6faf 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java @@ -531,7 +531,7 @@ class AdapterProperties { return; } - if (Flags.cleanupLeOnlyDeviceType() && deviceType != BluetoothDevice.DEVICE_TYPE_LE) { + if (deviceType != BluetoothDevice.DEVICE_TYPE_LE) { return; } @@ -547,12 +547,8 @@ class AdapterProperties { boolean removeExisting = false; if (identityAddress.equals(existingIdentityAddress) && !address.equals(existingAddress)) { - if (Flags.cleanupLeOnlyDeviceType()) { - // Existing device record should be removed only if the device type is LE-only - removeExisting = (existingDeviceType == BluetoothDevice.DEVICE_TYPE_LE); - } else { - removeExisting = true; - } + // Existing device record should be removed only if the device type is LE-only + removeExisting = (existingDeviceType == BluetoothDevice.DEVICE_TYPE_LE); } if (removeExisting) { diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java index c48e8b8e3c..bd64fb6c7b 100644 --- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java +++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java @@ -42,8 +42,6 @@ import android.os.ParcelUuid; import android.os.SystemProperties; import android.util.Log; -import androidx.annotation.NonNull; - import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.R; import com.android.bluetooth.Utils; @@ -290,10 +288,16 @@ public class RemoteDevices { @VisibleForTesting DeviceProperties addDeviceProperties(byte[] address) { synchronized (mDevices) { + String key = Utils.getAddressStringFromByte(address); + if (Flags.fixAddDeviceProperties() && mDevices.containsKey(key)) { + debugLog("Properties for device " + key + " are already added"); + return mDevices.get(key); + } + DeviceProperties prop = new DeviceProperties(); prop.setDevice(mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address))); prop.setAddress(address); - String key = Utils.getAddressStringFromByte(address); + DeviceProperties pv = mDevices.put(key, prop); if (pv == null) { @@ -1315,7 +1319,6 @@ public class RemoteDevices { mAdapterService.aclStateChangeBroadcastCallback(connectionChangeConsumer); } - @NonNull private void sendPairingCancelIntent(BluetoothDevice device) { Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 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 c93e10febd..0683607ef5 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java @@ -117,6 +117,9 @@ public class LeAudioService extends ProfileService { // Timeout for state machine thread join, to prevent potential ANR. private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000; + /* 5 seconds timeout for Broadcast streaming state transition */ + private static final int CREATE_BROADCAST_TIMEOUT_MS = 5000; + private static LeAudioService sLeAudioService; /** Indicates group audio support for none direction */ @@ -151,9 +154,6 @@ public class LeAudioService extends ProfileService { .setSampleRate(BluetoothLeAudioCodecConfig.SAMPLE_RATE_48000) .build(); - /* 5 seconds timeout for Broadcast streaming state transition */ - private static final int DIALING_OUT_TIMEOUT_MS = 5000; - private AdapterService mAdapterService; private DatabaseManager mDatabaseManager; private HandlerThread mStateMachinesThread; @@ -165,6 +165,8 @@ public class LeAudioService extends ProfileService { private final ReentrantReadWriteLock mGroupReadWriteLock = new ReentrantReadWriteLock(); private final Lock mGroupReadLock = mGroupReadWriteLock.readLock(); private final Lock mGroupWriteLock = mGroupReadWriteLock.writeLock(); + private CreateBroadcastTimeoutEvent mCreateBroadcastTimeoutEvent; + ServiceFactory mServiceFactory = new ServiceFactory(); private final LeAudioNativeInterface mNativeInterface; @@ -182,7 +184,6 @@ public class LeAudioService extends ProfileService { BluetoothDevice mLeAudioDeviceInactivatedForHfpHandover = null; LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null; - private DialingOutTimeoutEvent mDialingOutTimeoutEvent = null; @VisibleForTesting AudioManager mAudioManager; LeAudioTmapGattServer mTmapGattServer; int mTmapRoleMask; @@ -653,7 +654,7 @@ public class LeAudioService extends ProfileService { mIsSinkStreamMonitorModeEnabled = false; mIsBroadcastPausedFromOutside = false; - clearBroadcastTimeoutCallback(); + clearCreateBroadcastTimeoutCallback(); if (!Flags.leaudioSynchronizeStart()) { mHandler.removeCallbacks(this::init); @@ -1148,29 +1149,48 @@ public class LeAudioService extends ProfileService { return LE_AUDIO_GROUP_ID_INVALID; } - /** - * Creates LeAudio Broadcast instance with BluetoothLeBroadcastSettings. - * - * @param broadcastSettings broadcast settings for this broadcast source - */ - public void createBroadcast(BluetoothLeBroadcastSettings broadcastSettings) { + private int canBroadcastBeCreated(BluetoothLeBroadcastSettings broadcastSettings) { if (mBroadcastDescriptors.size() >= getMaximumNumberOfBroadcasts()) { Log.w( TAG, "createBroadcast reached maximum allowed broadcasts number: " + getMaximumNumberOfBroadcasts()); - mHandler.post( - () -> - notifyBroadcastStartFailed( - BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); - return; + return BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES; + } + + byte[] broadcastCode = broadcastSettings.getBroadcastCode(); + if (broadcastCode != null && ((broadcastCode.length > 16) || (broadcastCode.length < 4))) { + Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long."); + return BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_CODE; + } + + List<BluetoothLeBroadcastSubgroupSettings> settingsList = + broadcastSettings.getSubgroupSettings(); + if (settingsList == null || settingsList.size() < 1) { + Log.d(TAG, "subgroup settings is not valid value"); + return BluetoothStatusCodes.ERROR_BAD_PARAMETERS; } + return BluetoothStatusCodes.SUCCESS; + } + + /** + * Creates LeAudio Broadcast instance with BluetoothLeBroadcastSettings. + * + * @param broadcastSettings broadcast settings for this broadcast source + */ + public void createBroadcast(BluetoothLeBroadcastSettings broadcastSettings) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } + int canBroadcastBeCreatedReturnCode = canBroadcastBeCreated(broadcastSettings); + if (canBroadcastBeCreatedReturnCode != BluetoothStatusCodes.SUCCESS) { + mHandler.post(() -> notifyBroadcastStartFailed(canBroadcastBeCreatedReturnCode)); + return; + } + if (mAwaitingBroadcastCreateResponse) { mCreateBroadcastQueue.add(broadcastSettings); Log.i(TAG, "Broadcast creation queued due to waiting for a previous request response."); @@ -1192,21 +1212,6 @@ public class LeAudioService extends ProfileService { } } - byte[] broadcastCode = broadcastSettings.getBroadcastCode(); - boolean isEncrypted = (broadcastCode != null) && (broadcastCode.length != 0); - if (isEncrypted) { - if ((broadcastCode.length > 16) || (broadcastCode.length < 4)) { - Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long."); - return; - } - } - - List<BluetoothLeBroadcastSubgroupSettings> settingsList = - broadcastSettings.getSubgroupSettings(); - if (settingsList == null || settingsList.size() < 1) { - Log.d(TAG, "subgroup settings is not valid value"); - return; - } mBroadcastSessionStats.put( INVALID_BROADCAST_ID, new LeAudioBroadcastSessionStats(broadcastSettings, SystemClock.elapsedRealtime())); @@ -1214,19 +1219,37 @@ public class LeAudioService extends ProfileService { BluetoothLeAudioContentMetadata publicMetadata = broadcastSettings.getPublicBroadcastMetadata(); - Log.i(TAG, "createBroadcast: isEncrypted=" + (isEncrypted ? "true" : "false")); + byte[] broadcastCode = broadcastSettings.getBroadcastCode(); + Log.i( + TAG, + "createBroadcast: isEncrypted=" + + (((broadcastCode != null) && (broadcastCode.length != 0)) + ? "true" + : "false")); mAwaitingBroadcastCreateResponse = true; if (leaudioBigDependsOnAudioState()) { mCreateBroadcastQueue.add(broadcastSettings); } + + if (leaudioBigDependsOnAudioState()) { + /* Start timeout to recover from stucked/error create Broadcast operation */ + if (mCreateBroadcastTimeoutEvent != null) { + Log.w(TAG, "CreateBroadcastTimeoutEvent already scheduled"); + } else { + mCreateBroadcastTimeoutEvent = new CreateBroadcastTimeoutEvent(); + mHandler.postDelayed(mCreateBroadcastTimeoutEvent, CREATE_BROADCAST_TIMEOUT_MS); + } + } + mLeAudioBroadcasterNativeInterface.createBroadcast( broadcastSettings.isPublicBroadcast(), broadcastSettings.getBroadcastName(), broadcastCode, publicMetadata == null ? null : publicMetadata.getRawMetadata(), - getBroadcastAudioQualityPerSinkCapabilities(settingsList), - settingsList.stream() + getBroadcastAudioQualityPerSinkCapabilities( + broadcastSettings.getSubgroupSettings()), + broadcastSettings.getSubgroupSettings().stream() .map(s -> s.getContentMetadata().getRawMetadata()) .toArray(byte[][]::new)); } @@ -1280,8 +1303,8 @@ public class LeAudioService extends ProfileService { Log.d(TAG, "startBroadcast"); /* Start timeout to recover from stucked/error start Broadcast operation */ - mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(broadcastId); - mHandler.postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS); + mCreateBroadcastTimeoutEvent = new CreateBroadcastTimeoutEvent(broadcastId); + mHandler.postDelayed(mCreateBroadcastTimeoutEvent, CREATE_BROADCAST_TIMEOUT_MS); mLeAudioBroadcasterNativeInterface.startBroadcast(broadcastId); } @@ -3181,19 +3204,19 @@ public class LeAudioService extends ProfileService { setActiveDevice(unicastDevice); } - void clearBroadcastTimeoutCallback() { + private void clearCreateBroadcastTimeoutCallback() { if (mHandler == null) { Log.e(TAG, "No callback handler"); return; } /* Timeout callback already cleared */ - if (mDialingOutTimeoutEvent == null) { + if (mCreateBroadcastTimeoutEvent == null) { return; } - mHandler.removeCallbacks(mDialingOutTimeoutEvent); - mDialingOutTimeoutEvent = null; + mHandler.removeCallbacks(mCreateBroadcastTimeoutEvent); + mCreateBroadcastTimeoutEvent = null; } void notifyAudioFrameworkForCodecConfigUpdate( @@ -3669,7 +3692,10 @@ public class LeAudioService extends ProfileService { if (!leaudioUseAudioModeListener()) { mQueuedInCallValue = Optional.empty(); } - startBroadcast(mBroadcastIdDeactivatedForUnicastTransition.get()); + if (!leaudioBigDependsOnAudioState()) { + startBroadcast( + mBroadcastIdDeactivatedForUnicastTransition.get()); + } mBroadcastIdDeactivatedForUnicastTransition = Optional.empty(); } @@ -3729,9 +3755,10 @@ public class LeAudioService extends ProfileService { mBroadcastSessionStats.put(broadcastId, sessionStats); } - // Start sending the actual stream - startBroadcast(broadcastId); - + if (!leaudioBigDependsOnAudioState()) { + // Start sending the actual stream + startBroadcast(broadcastId); + } } else { // TODO: Improve reason reporting or extend the native stack event with reason code Log.e( @@ -3744,7 +3771,9 @@ public class LeAudioService extends ProfileService { if ((mUnicastGroupIdDeactivatedForBroadcastTransition != LE_AUDIO_GROUP_ID_INVALID) && mCreateBroadcastQueue.isEmpty() && (!Objects.equals(device, mActiveBroadcastAudioDevice))) { - clearBroadcastTimeoutCallback(); + if (!leaudioBigDependsOnAudioState()) { + clearCreateBroadcastTimeoutCallback(); + } updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); } @@ -3755,6 +3784,9 @@ public class LeAudioService extends ProfileService { .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_CREATE_FAILED); } + if (leaudioBigDependsOnAudioState()) { + clearCreateBroadcastTimeoutCallback(); + } mAwaitingBroadcastCreateResponse = false; // In case if there were additional calls to create broadcast @@ -3883,7 +3915,9 @@ public class LeAudioService extends ProfileService { sessionStats.updateSessionStreamingTime(SystemClock.elapsedRealtime()); } - clearBroadcastTimeoutCallback(); + if (!leaudioBigDependsOnAudioState()) { + clearCreateBroadcastTimeoutCallback(); + } if (previousState == LeAudioStackEvent.BROADCAST_STATE_PAUSED) { if (bassClientService != null) { @@ -5279,45 +5313,64 @@ public class LeAudioService extends ProfileService { return audioFrameworkCalls; } - class DialingOutTimeoutEvent implements Runnable { + private class CreateBroadcastTimeoutEvent implements Runnable { Integer mBroadcastId; - DialingOutTimeoutEvent(Integer broadcastId) { + CreateBroadcastTimeoutEvent() {} + + CreateBroadcastTimeoutEvent(Integer broadcastId) { mBroadcastId = broadcastId; } @Override public void run() { - Log.w(TAG, "Failed to start Broadcast in time: " + mBroadcastId); - - mDialingOutTimeoutEvent = null; + if (leaudioBigDependsOnAudioState()) { + Log.w(TAG, "Failed to start Broadcast in time"); - if (getLeAudioService() == null) { - Log.e(TAG, "DialingOutTimeoutEvent: No LE Audio service"); - return; - } + if (getLeAudioService() == null) { + Log.e(TAG, "CreateBroadcastTimeoutEvent: No LE Audio service"); + return; + } - if (Flags.leaudioBroadcastDestroyAfterTimeout()) { - LeAudioBroadcastSessionStats sessionStats = - mBroadcastSessionStats.get(mBroadcastId); - if (sessionStats != null) { - sessionStats.updateSessionStatus( - BluetoothStatsLog - .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_STREAMING_FAILED); - // log once destroyed + if (sLeAudioService.mHandler == null) { + Log.w(TAG, "CreateBroadcastTimeoutEvent: No handler"); + return; } - transitionFromBroadcastToUnicast(); - destroyBroadcast(mBroadcastId); + + mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); } else { - if (mActiveBroadcastAudioDevice != null) { - updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); + Log.w(TAG, "Failed to start Broadcast in time: " + mBroadcastId); + + mCreateBroadcastTimeoutEvent = null; + + if (getLeAudioService() == null) { + Log.e(TAG, "CreateBroadcastTimeoutEvent: No LE Audio service"); + return; } - mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); - logBroadcastSessionStatsWithStatus( - mBroadcastId, - BluetoothStatsLog - .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_STREAMING_FAILED); + if (Flags.leaudioBroadcastDestroyAfterTimeout()) { + LeAudioBroadcastSessionStats sessionStats = + mBroadcastSessionStats.get(mBroadcastId); + if (sessionStats != null) { + sessionStats.updateSessionStatus( + BluetoothStatsLog + .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_STREAMING_FAILED); + // log once destroyed + } + transitionFromBroadcastToUnicast(); + destroyBroadcast(mBroadcastId); + } else { + if (mActiveBroadcastAudioDevice != null) { + updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); + } + + mHandler.post( + () -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); + logBroadcastSessionStatsWithStatus( + mBroadcastId, + BluetoothStatsLog + .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_STREAMING_FAILED); + } } } } 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 acf80cfd76..657ea4d5a9 100644 --- a/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java +++ b/android/app/src/com/android/bluetooth/le_scan/MsftAdvMonitor.java @@ -70,7 +70,7 @@ class MsftAdvMonitor { mMonitor.rssi_sampling_period = RSSI_SAMPLING_PERIOD; mMonitor.condition_type = MSFT_CONDITION_TYPE_PATTERNS; - if (filter.getServiceDataUuid() != null && filter.getServiceDataMask() == null) { + if (filter.getServiceDataUuid() != null && dataMaskIsEmpty(filter.getServiceDataMask())) { Pattern pattern = new Pattern(); pattern.ad_type = (byte) 0x16; // Bluetooth Core Spec Part A, Section 1 pattern.start_byte = FILTER_PATTERN_START_POSITION; @@ -86,8 +86,7 @@ class MsftAdvMonitor { mPatterns.add(pattern); } else if (filter.getAdvertisingData() != null && filter.getAdvertisingData().length != 0 - && (filter.getAdvertisingDataMask() == null - || filter.getAdvertisingDataMask().length == 0)) { + && dataMaskIsEmpty(filter.getAdvertisingDataMask())) { Pattern pattern = new Pattern(); pattern.ad_type = (byte) filter.getAdvertisingDataType(); pattern.start_byte = FILTER_PATTERN_START_POSITION; @@ -112,4 +111,10 @@ class MsftAdvMonitor { Address getAddress() { return mAddress; } + + private boolean dataMaskIsEmpty(byte[] mask) { + if (mask == null || mask.length == 0) return true; + if (mask.length == 1 && mask[0] == 0) return true; + return false; + } } 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 573b4f49d2..09f3626ad7 100644 --- a/android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java +++ b/android/app/src/com/android/bluetooth/le_scan/TransitionalScanHelper.java @@ -463,12 +463,7 @@ public class TransitionalScanHelper { } } catch (RemoteException | PendingIntent.CanceledException e) { Log.e(TAG, "Exception: " + e); - if (Flags.leScanFixRemoteException()) { - handleDeadScanClient(client); - } else { - mScannerMap.remove(client.scannerId); - mScanManager.stopScan(client.scannerId); - } + handleDeadScanClient(client); } } } @@ -772,12 +767,7 @@ public class TransitionalScanHelper { } } catch (RemoteException | PendingIntent.CanceledException e) { Log.e(TAG, "Exception: " + e); - if (Flags.leScanFixRemoteException()) { - handleDeadScanClient(client); - } else { - mScannerMap.remove(client.scannerId); - mScanManager.stopScan(client.scannerId); - } + handleDeadScanClient(client); } } @@ -1518,15 +1508,7 @@ public class TransitionalScanHelper { ScanClient client = getScanClient(mScannerId); if (client != null) { - if (Flags.leScanFixRemoteException()) { - handleDeadScanClient(client); - } else { - client.appDied = true; - if (client.stats != null) { - client.stats.isAppDead = true; - } - stopScanInternal(client.scannerId); - } + handleDeadScanClient(client); } } diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java index f70903f1be..e0fce72338 100644 --- a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java +++ b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java @@ -3352,6 +3352,7 @@ public class BluetoothMapContentObserver { return handle; } + @SuppressWarnings("EnumOrdinal") // remove entire usage of internal intent public long sendMmsMessage( String folder, String[] toAddress, @@ -4090,6 +4091,7 @@ public class BluetoothMapContentObserver { } } + @SuppressWarnings("EnumOrdinal") // remove entire usage of internal intent public static void actionMessageSentDisconnected(Context context, Intent intent, int result) { TYPE type = TYPE.fromOrdinal( @@ -4277,6 +4279,7 @@ public class BluetoothMapContentObserver { } } + @SuppressWarnings("EnumOrdinal") // remove entire usage of internal intent public boolean handleSmsSendIntent(Context context, Intent intent) { TYPE type = TYPE.fromOrdinal( diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java index 87145b17d0..8cbd32cfba 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java @@ -141,7 +141,7 @@ class BluetoothOppNotification { private final HashMap<String, NotificationItem> mNotifications = new HashMap<>(); - private NotificationUpdateThread mUpdateNotificationThread; + @VisibleForTesting NotificationUpdateThread mUpdateNotificationThread; private int mPendingUpdate = 0; diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java index 559654de4f..a8c653db5c 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java @@ -135,7 +135,7 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti private BluetoothShareContentObserver mObserver; /** Class to handle Notification Manager updates */ - private BluetoothOppNotification mNotifier; + @VisibleForTesting BluetoothOppNotification mNotifier; private boolean mPendingUpdate; diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java index b66295d43e..5565fbd87d 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java @@ -280,6 +280,7 @@ public class BluetoothPbapCallLogComposer implements AutoCloseable { } /** Closes the composer, releasing all of its resources. */ + @Override public void close() { if (mCursor != null) { try { diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java index ac65f6c78e..8f894848dd 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java @@ -194,6 +194,7 @@ public class BluetoothPbapSimVcardManager implements AutoCloseable { } /** Closes the manager, releasing all of its resources. */ + @Override public void close() { if (mCursor != null) { try { diff --git a/android/app/src/com/android/bluetooth/tbs/TbsGatt.java b/android/app/src/com/android/bluetooth/tbs/TbsGatt.java index af1cc02291..803b249a3d 100644 --- a/android/app/src/com/android/bluetooth/tbs/TbsGatt.java +++ b/android/app/src/com/android/bluetooth/tbs/TbsGatt.java @@ -1036,6 +1036,7 @@ public class TbsGatt { return mTbsService.getDeviceAuthorization(device); } + @SuppressWarnings("EnumOrdinal") private void onRejectedAuthorizationGattOperation(BluetoothDevice device, GattOpContext op) { UUID charUuid = (op.mCharacteristic != null @@ -1102,7 +1103,7 @@ public class TbsGatt { boolean allowToReadRealValue = false; byte[] buffer = null; - /* Allow only some informations to be disclosed at this stage. */ + /* Allow only some information to be disclosed at this stage. */ if (charUuid.equals(UUID_BEARER_PROVIDER_NAME)) { ByteBuffer bb = ByteBuffer.allocate(0).order(ByteOrder.LITTLE_ENDIAN); bb.put("".getBytes()); diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java index 5ebd46026b..99f296b9be 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java @@ -19,6 +19,14 @@ package com.android.bluetooth.vc; import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothDevice.BOND_BONDED; +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.STATE_CONNECTED; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static java.util.Objects.requireNonNull; @@ -31,7 +39,6 @@ import android.bluetooth.IBluetoothLeAudio; import android.bluetooth.IBluetoothVolumeControl; import android.bluetooth.IBluetoothVolumeControlCallback; import android.content.AttributionSource; -import android.content.Context; import android.media.AudioManager; import android.os.Handler; import android.os.HandlerThread; @@ -70,27 +77,28 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class VolumeControlService extends ProfileService { - private static final String TAG = "VolumeControlService"; + private static final String TAG = VolumeControlService.class.getSimpleName(); - // Timeout for state machine thread join, to prevent potential ANR. private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000; - private static final int LE_AUDIO_MAX_VOL = 255; + /* As defined by Volume Control Service 1.0.1, 3.3.1. Volume Flags behavior. + * 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 VolumeControlService sVolumeControlService; - private AdapterService mAdapterService; - private DatabaseManager mDatabaseManager; - private HandlerThread mStateMachinesThread; - private Handler mHandler = null; - @VisibleForTesting @GuardedBy("mCallbacks") final RemoteCallbackList<IBluetoothVolumeControlCallback> mCallbacks = new RemoteCallbackList<>(); - VolumeControlNativeInterface mVolumeControlNativeInterface; - @VisibleForTesting AudioManager mAudioManager; + private final AdapterService mAdapterService; + private final AudioManager mAudioManager; + private final DatabaseManager mDatabaseManager; + private final Handler mHandler; + private final HandlerThread mStateMachinesThread; + private final Looper mStateMachinesLooper; + private final VolumeControlNativeInterface mNativeInterface; private final Map<BluetoothDevice, VolumeControlStateMachine> mStateMachines = new HashMap<>(); private final Map<BluetoothDevice, VolumeControlOffsetDescriptor> mAudioOffsets = @@ -100,15 +108,34 @@ public class VolumeControlService extends ProfileService { private final Map<Integer, Boolean> mGroupMuteCache = new HashMap<>(); private final Map<BluetoothDevice, Integer> mDeviceVolumeCache = new HashMap<>(); - /* As defined by Volume Control Service 1.0.1, 3.3.1. Volume Flags behavior. - * User Set Volume Setting means that remote keeps volume in its cache. - */ - @VisibleForTesting static final int VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK = 0x01; - @VisibleForTesting ServiceFactory mFactory = new ServiceFactory(); - public VolumeControlService(Context ctx) { - super(ctx); + public VolumeControlService(AdapterService adapterService) { + this(adapterService, null, VolumeControlNativeInterface.getInstance()); + } + + @VisibleForTesting + VolumeControlService( + AdapterService adapterService, + Looper looper, + VolumeControlNativeInterface nativeInterface) { + super(requireNonNull(adapterService)); + mAdapterService = adapterService; + mDatabaseManager = requireNonNull(mAdapterService.getDatabase()); + mNativeInterface = requireNonNull(nativeInterface); + mAudioManager = requireNonNull(getSystemService(AudioManager.class)); + if (looper == null) { + mHandler = new Handler(requireNonNull(Looper.getMainLooper())); + mStateMachinesThread = new HandlerThread("VolumeControlService.StateMachines"); + mStateMachinesThread.start(); + mStateMachinesLooper = mStateMachinesThread.getLooper(); + } else { + mHandler = new Handler(looper); + mStateMachinesThread = null; + mStateMachinesLooper = looper; + } + setVolumeControlService(this); + mNativeInterface.init(); } public static boolean isEnabled() { @@ -121,44 +148,8 @@ public class VolumeControlService extends ProfileService { } @Override - public void start() { - Log.d(TAG, "start()"); - if (sVolumeControlService != null) { - throw new IllegalStateException("start() called twice"); - } - - // Get AdapterService, VolumeControlNativeInterface, DatabaseManager, AudioManager. - // None of them can be null. - mAdapterService = requireNonNull(AdapterService.getAdapterService()); - mDatabaseManager = requireNonNull(mAdapterService.getDatabase()); - mVolumeControlNativeInterface = requireNonNull(VolumeControlNativeInterface.getInstance()); - mAudioManager = requireNonNull(getSystemService(AudioManager.class)); - - // Start handler thread for state machines - mHandler = new Handler(Looper.getMainLooper()); - mStateMachines.clear(); - mStateMachinesThread = new HandlerThread("VolumeControlService.StateMachines"); - mStateMachinesThread.start(); - - mAudioOffsets.clear(); - mGroupVolumeCache.clear(); - mGroupMuteCache.clear(); - mDeviceVolumeCache.clear(); - - // Mark service as started - setVolumeControlService(this); - - // Initialize native interface - mVolumeControlNativeInterface.init(); - } - - @Override public void stop() { Log.d(TAG, "stop()"); - if (sVolumeControlService == null) { - Log.w(TAG, "stop() called before start()"); - return; - } // Mark service as stopped setVolumeControlService(null); @@ -167,7 +158,6 @@ public class VolumeControlService extends ProfileService { synchronized (mStateMachines) { for (VolumeControlStateMachine sm : mStateMachines.values()) { sm.doQuit(); - sm.cleanup(); } mStateMachines.clear(); } @@ -176,44 +166,26 @@ public class VolumeControlService 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 remove all queued messages. - if (mHandler != null) { - mHandler.removeCallbacksAndMessages(null); - mHandler = null; - } + mHandler.removeCallbacksAndMessages(null); // Cleanup native interface - mVolumeControlNativeInterface.cleanup(); - mVolumeControlNativeInterface = null; + mNativeInterface.cleanup(); mAudioOffsets.clear(); mGroupVolumeCache.clear(); mGroupMuteCache.clear(); mDeviceVolumeCache.clear(); - // Clear AdapterService, VolumeControlNativeInterface - mAudioManager = null; - mVolumeControlNativeInterface = null; - mAdapterService = null; - synchronized (mCallbacks) { - if (mCallbacks != null) { - mCallbacks.kill(); - } + mCallbacks.kill(); } } - @Override - public void cleanup() { - Log.d(TAG, "cleanup()"); - } - /** * Get the VolumeControlService instance * @@ -244,7 +216,7 @@ public class VolumeControlService extends ProfileService { return false; } - if (getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { + if (getConnectionPolicy(device) == CONNECTION_POLICY_FORBIDDEN) { return false; } final ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device); @@ -260,7 +232,7 @@ public class VolumeControlService extends ProfileService { if (smConnect == null) { Log.e(TAG, "Cannot connect to " + device + " : no state machine"); } - smConnect.sendMessage(VolumeControlStateMachine.CONNECT); + smConnect.sendMessage(VolumeControlStateMachine.MESSAGE_CONNECT); } return true; @@ -274,7 +246,7 @@ public class VolumeControlService extends ProfileService { synchronized (mStateMachines) { VolumeControlStateMachine sm = getOrCreateStateMachine(device); if (sm != null) { - sm.sendMessage(VolumeControlStateMachine.DISCONNECT); + sm.sendMessage(VolumeControlStateMachine.MESSAGE_DISCONNECT); } } @@ -317,11 +289,11 @@ public class VolumeControlService extends ProfileService { int bondState = mAdapterService.getBondState(device); // Allow this connection only if the device is bonded. Any attempt to connect while // bonding would potentially lead to an unauthorized connection. - if (bondState != BluetoothDevice.BOND_BONDED) { + if (bondState != BOND_BONDED) { Log.w(TAG, "okToConnect: return false, bondState=" + bondState); return false; - } else if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_UNKNOWN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + } else if (connectionPolicy != CONNECTION_POLICY_UNKNOWN + && connectionPolicy != CONNECTION_POLICY_ALLOWED) { // Otherwise, reject the connection if connectionPolicy is not valid. Log.w(TAG, "okToConnect: return false, connectionPolicy=" + connectionPolicy); return false; @@ -344,7 +316,7 @@ public class VolumeControlService extends ProfileService { if (!Utils.arrayContains(featureUuids, BluetoothUuid.VOLUME_CONTROL)) { continue; } - int connectionState = BluetoothProfile.STATE_DISCONNECTED; + int connectionState = STATE_DISCONNECTED; VolumeControlStateMachine sm = mStateMachines.get(device); if (sm != null) { connectionState = sm.getConnectionState(); @@ -380,7 +352,7 @@ public class VolumeControlService extends ProfileService { synchronized (mStateMachines) { VolumeControlStateMachine sm = mStateMachines.get(device); if (sm == null) { - return BluetoothProfile.STATE_DISCONNECTED; + return STATE_DISCONNECTED; } return sm.getConnectionState(); } @@ -404,9 +376,9 @@ public class VolumeControlService extends ProfileService { Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy); mDatabaseManager.setProfileConnectionPolicy( device, BluetoothProfile.VOLUME_CONTROL, connectionPolicy); - if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + if (connectionPolicy == CONNECTION_POLICY_ALLOWED) { connect(device); - } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { + } else if (connectionPolicy == CONNECTION_POLICY_FORBIDDEN) { disconnect(device); } return true; @@ -465,7 +437,7 @@ public class VolumeControlService extends ProfileService { return; } - mVolumeControlNativeInterface.setExtAudioOutVolumeOffset(device, instanceId, volumeOffset); + mNativeInterface.setExtAudioOutVolumeOffset(device, instanceId, volumeOffset); } void setDeviceVolume(BluetoothDevice device, int volume, boolean isGroupOp) { @@ -478,18 +450,19 @@ public class VolumeControlService extends ProfileService { Log.e(TAG, "leAudioService not available"); return; } - int groupId = leAudioService.getGroupId(device); - if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) { - Log.e(TAG, "Device not a part of a group"); - return; - } if (isGroupOp) { + int groupId = leAudioService.getGroupId(device); + if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) { + Log.e(TAG, "Device not a part of a group"); + return; + } + setGroupVolume(groupId, volume); } else { Log.i(TAG, "Setting individual device volume"); mDeviceVolumeCache.put(device, volume); - mVolumeControlNativeInterface.setVolume(device, volume); + mNativeInterface.setVolume(device, volume); } } @@ -500,7 +473,7 @@ public class VolumeControlService extends ProfileService { } mGroupVolumeCache.put(groupId, volume); - mVolumeControlNativeInterface.setGroupVolume(groupId, volume); + mNativeInterface.setGroupVolume(groupId, volume); // We only receive the volume change and mute state needs to be acquired manually Boolean isGroupMute = mGroupMuteCache.getOrDefault(groupId, false); @@ -508,7 +481,7 @@ public class VolumeControlService extends ProfileService { /* Note: AudioService keeps volume levels for each stream and for each device type, * however it stores the mute state only for the stream type but not for each individual - * device type. When active device changes, it's volume level gets aplied, but mute state + * device type. When active device changes, it's volume level gets applied, but mute state * is not, but can be either derived from the volume level or just unmuted like for A2DP. * Also setting volume level > 0 to audio system will implicitly unmute the stream. * However LeAudio devices can keep their volume level high, while keeping it mute so we @@ -580,21 +553,21 @@ public class VolumeControlService extends ProfileService { } public void mute(BluetoothDevice device) { - mVolumeControlNativeInterface.mute(device); + mNativeInterface.mute(device); } public void muteGroup(int groupId) { mGroupMuteCache.put(groupId, true); - mVolumeControlNativeInterface.muteGroup(groupId); + mNativeInterface.muteGroup(groupId); } public void unmute(BluetoothDevice device) { - mVolumeControlNativeInterface.unmute(device); + mNativeInterface.unmute(device); } public void unmuteGroup(int groupId) { mGroupMuteCache.put(groupId, false); - mVolumeControlNativeInterface.unmuteGroup(groupId); + mNativeInterface.unmuteGroup(groupId); } void notifyNewCallbackOfKnownVolumeInfo(IBluetoothVolumeControlCallback callback) { @@ -670,7 +643,7 @@ public class VolumeControlService extends ProfileService { if (sm == null) { return; } - if (sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) { + if (sm.getConnectionState() != STATE_CONNECTED) { return; } } @@ -680,7 +653,7 @@ public class VolumeControlService extends ProfileService { synchronized (mStateMachines) { VolumeControlStateMachine sm = mStateMachines.get(device); if (sm != null) { - can_change_volume = (sm.getConnectionState() == BluetoothProfile.STATE_CONNECTED); + can_change_volume = (sm.getConnectionState() == STATE_CONNECTED); } } @@ -691,15 +664,15 @@ public class VolumeControlService extends ProfileService { groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME); if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) { Log.i(TAG, "Setting value:" + groupVolume + " to " + device); - mVolumeControlNativeInterface.setVolume(device, groupVolume); + mNativeInterface.setVolume(device, groupVolume); } Boolean isGroupMuted = mGroupMuteCache.getOrDefault(groupId, false); Log.i(TAG, "Setting mute:" + isGroupMuted + " to " + device); if (isGroupMuted) { - mVolumeControlNativeInterface.mute(device); + mNativeInterface.mute(device); } else { - mVolumeControlNativeInterface.unmute(device); + mNativeInterface.unmute(device); } } } @@ -865,21 +838,20 @@ public class VolumeControlService extends ProfileService { synchronized (mStateMachines) { VolumeControlStateMachine sm = mStateMachines.get(device); if (sm != null) { - can_change_volume = - (sm.getConnectionState() == BluetoothProfile.STATE_CONNECTED); + can_change_volume = (sm.getConnectionState() == STATE_CONNECTED); } } if (can_change_volume && (groupVolume != volume)) { Log.i(TAG, "Setting value:" + groupVolume + " to " + device); - mVolumeControlNativeInterface.setVolume(device, groupVolume); + mNativeInterface.setVolume(device, groupVolume); } if (can_change_volume && (groupMute != mute)) { Log.i(TAG, "Setting mute:" + groupMute + " to " + device); if (groupMute) { - mVolumeControlNativeInterface.mute(device); + mNativeInterface.mute(device); } else { - mVolumeControlNativeInterface.unmute(device); + mNativeInterface.unmute(device); } } } else { @@ -925,19 +897,16 @@ public class VolumeControlService extends ProfileService { Log.d(TAG, "Volume mode: " + mode + "0: normal, 1: ring, 2,3: call"); - switch (mode) { - case AudioManager.MODE_IN_COMMUNICATION: - case AudioManager.MODE_IN_CALL: - return AudioManager.STREAM_VOICE_CALL; - case AudioManager.MODE_RINGTONE: + return switch (mode) { + case AudioManager.MODE_IN_CALL, AudioManager.MODE_IN_COMMUNICATION -> { + yield AudioManager.STREAM_VOICE_CALL; + } + case AudioManager.MODE_RINGTONE -> { Log.d(TAG, " Update during ringtone applied to voice call"); - return AudioManager.STREAM_VOICE_CALL; - case AudioManager.MODE_NORMAL: - default: - // other conditions will influence the stream type choice, read on... - break; - } - return AudioManager.STREAM_MUSIC; + yield AudioManager.STREAM_VOICE_CALL; + } + default -> AudioManager.STREAM_MUSIC; + }; } void handleExternalOutputs(BluetoothDevice device, int numberOfExternalOutputs) { @@ -1277,12 +1246,9 @@ public class VolumeControlService extends ProfileService { if (stackEvent.type == VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) { switch (stackEvent.valueInt1) { - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTED: - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTING: + case STATE_CONNECTED, STATE_CONNECTING -> { sm = getOrCreateStateMachine(device); - break; - default: - break; + } } } } @@ -1290,7 +1256,7 @@ public class VolumeControlService extends ProfileService { Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent); return; } - sm.sendMessage(VolumeControlStateMachine.STACK_EVENT, stackEvent); + sm.sendMessage(VolumeControlStateMachine.MESSAGE_STACK_EVENT, stackEvent); } } @@ -1307,11 +1273,9 @@ public class VolumeControlService extends ProfileService { Log.d(TAG, "Creating a new state machine for " + device); sm = - VolumeControlStateMachine.make( - device, - this, - mVolumeControlNativeInterface, - mStateMachinesThread.getLooper()); + new VolumeControlStateMachine( + this, device, mNativeInterface, mStateMachinesLooper); + sm.start(); mStateMachines.put(device, sm); return sm; } @@ -1392,7 +1356,7 @@ public class VolumeControlService extends ProfileService { void bondStateChanged(BluetoothDevice device, int bondState) { Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState); // Remove state machine if the bonding for a device is removed - if (bondState != BluetoothDevice.BOND_NONE) { + if (bondState != BOND_NONE) { return; } @@ -1401,7 +1365,7 @@ public class VolumeControlService extends ProfileService { if (sm == null) { return; } - if (sm.getConnectionState() != BluetoothProfile.STATE_DISCONNECTED) { + if (sm.getConnectionState() != STATE_DISCONNECTED) { Log.i(TAG, "Disconnecting device because it was unbonded."); disconnect(device); return; @@ -1421,7 +1385,6 @@ public class VolumeControlService extends ProfileService { } Log.i(TAG, "removeStateMachine: removing state machine for device: " + device); sm.doQuit(); - sm.cleanup(); mStateMachines.remove(device); } } @@ -1450,13 +1413,13 @@ public class VolumeControlService extends ProfileService { } // Check if the device is disconnected - if unbond, remove the state machine - if (toState == BluetoothProfile.STATE_DISCONNECTED) { + if (toState == STATE_DISCONNECTED) { int bondState = mAdapterService.getBondState(device); - if (bondState == BluetoothDevice.BOND_NONE) { + if (bondState == BOND_NONE) { Log.d(TAG, device + " is unbond. Remove state machine"); removeStateMachine(device); } - } else if (toState == BluetoothProfile.STATE_CONNECTED) { + } 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) { @@ -1466,14 +1429,14 @@ public class VolumeControlService extends ProfileService { mGroupVolumeCache.getOrDefault( groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME); if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) { - mVolumeControlNativeInterface.setVolume(device, groupVolume); + mNativeInterface.setVolume(device, groupVolume); } Boolean groupMute = mGroupMuteCache.getOrDefault(groupId, false); if (groupMute) { - mVolumeControlNativeInterface.mute(device); + mNativeInterface.mute(device); } else { - mVolumeControlNativeInterface.unmute(device); + mNativeInterface.unmute(device); } } } else { @@ -1554,7 +1517,7 @@ public class VolumeControlService extends ProfileService { VolumeControlService service = getService(source); if (service == null) { - return BluetoothProfile.STATE_DISCONNECTED; + return STATE_DISCONNECTED; } return service.getConnectionState(device); @@ -1580,7 +1543,7 @@ public class VolumeControlService extends ProfileService { VolumeControlService service = getService(source); if (service == null) { - return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; + return CONNECTION_POLICY_UNKNOWN; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java b/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java index 62f8b702d7..d102952d27 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlStackEvent.java @@ -18,6 +18,7 @@ package com.android.bluetooth.vc; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; public class VolumeControlStackEvent { // Event types for STACK_EVENT message (coming from native) @@ -34,13 +35,6 @@ public class VolumeControlStackEvent { public static final int EVENT_TYPE_EXT_AUDIO_IN_DESCR_CHANGED = 10; public static final int EVENT_TYPE_EXT_AUDIO_IN_GAIN_PROPS_CHANGED = 11; - // Do not modify without updating the HAL bt_vc_aid.h files. - // Match up with enum class ConnectionState of bt_vc_aid.h. - static final int CONNECTION_STATE_DISCONNECTED = 0; - static final int CONNECTION_STATE_CONNECTING = 1; - static final int CONNECTION_STATE_CONNECTED = 2; - static final int CONNECTION_STATE_DISCONNECTING = 3; - public int type; public BluetoothDevice device; public int valueInt1; @@ -108,18 +102,7 @@ public class VolumeControlStackEvent { private static String eventTypeValue1ToString(int type, int value) { switch (type) { case EVENT_TYPE_CONNECTION_STATE_CHANGED: - switch (value) { - case CONNECTION_STATE_DISCONNECTED: - return "CONNECTION_STATE_DISCONNECTED"; - case CONNECTION_STATE_CONNECTING: - return "CONNECTION_STATE_CONNECTING"; - case CONNECTION_STATE_CONNECTED: - return "CONNECTION_STATE_CONNECTED"; - case CONNECTION_STATE_DISCONNECTING: - return "CONNECTION_STATE_DISCONNECTING"; - default: - return "UNKNOWN"; - } + return BluetoothProfile.getConnectionStateName(value); case EVENT_TYPE_VOLUME_STATE_CHANGED: return "{group_id:" + value + "}"; case EVENT_TYPE_DEVICE_AVAILABLE: @@ -143,18 +126,7 @@ public class VolumeControlStackEvent { private static String eventTypeValue2ToString(int type, int value) { switch (type) { case EVENT_TYPE_CONNECTION_STATE_CHANGED: - switch (value) { - case CONNECTION_STATE_DISCONNECTED: - return "CONNECTION_STATE_DISCONNECTED"; - case CONNECTION_STATE_CONNECTING: - return "CONNECTION_STATE_CONNECTING"; - case CONNECTION_STATE_CONNECTED: - return "CONNECTION_STATE_CONNECTED"; - case CONNECTION_STATE_DISCONNECTING: - return "CONNECTION_STATE_DISCONNECTING"; - default: - return "UNKNOWN"; - } + return BluetoothProfile.getConnectionStateName(value); case EVENT_TYPE_VOLUME_STATE_CHANGED: return "{volume:" + value + "}"; case EVENT_TYPE_DEVICE_AVAILABLE: diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java b/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java index 4a68e8f337..1e1ca9aa16 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlStateMachine.java @@ -18,6 +18,11 @@ package com.android.bluetooth.vc; import static android.Manifest.permission.BLUETOOTH_CONNECT; +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.BluetoothProfile.getConnectionStateName; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; @@ -35,37 +40,34 @@ import com.android.internal.util.StateMachine; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; +import java.time.Duration; import java.util.Scanner; -public class VolumeControlStateMachine extends StateMachine { +class VolumeControlStateMachine extends StateMachine { + private static final String TAG = VolumeControlStateMachine.class.getSimpleName(); - private static final String TAG = "VolumeControlStateMachine"; + static final int MESSAGE_CONNECT = 1; + static final int MESSAGE_DISCONNECT = 2; + static final int MESSAGE_STACK_EVENT = 101; + @VisibleForTesting static final int MESSAGE_CONNECT_TIMEOUT = 201; - static final int CONNECT = 1; - static final int DISCONNECT = 2; - @VisibleForTesting static final int STACK_EVENT = 101; - @VisibleForTesting static final int CONNECT_TIMEOUT = 201; + @VisibleForTesting static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(30); - // NOTE: the value is not "final" - it is modified in the unit tests - @VisibleForTesting static int sConnectTimeoutMs = 30000; // 30s + private final Disconnected mDisconnected; + private final Connecting mConnecting; + private final Disconnecting mDisconnecting; + private final Connected mConnected; + private final VolumeControlService mService; + private final VolumeControlNativeInterface mNativeInterface; + private final BluetoothDevice mDevice; - private Disconnected mDisconnected; - private Connecting mConnecting; - private Disconnecting mDisconnecting; - private Connected mConnected; private int mLastConnectionState = -1; - private VolumeControlService mService; - private VolumeControlNativeInterface mNativeInterface; - - private final BluetoothDevice mDevice; - VolumeControlStateMachine( - BluetoothDevice device, VolumeControlService svc, + BluetoothDevice device, VolumeControlNativeInterface nativeInterface, Looper looper) { - super(TAG, looper); mDevice = device; mService = svc; @@ -84,27 +86,11 @@ public class VolumeControlStateMachine extends StateMachine { setInitialState(mDisconnected); } - static VolumeControlStateMachine make( - BluetoothDevice device, - VolumeControlService svc, - VolumeControlNativeInterface nativeInterface, - Looper looper) { - Log.i(TAG, "make for device " + device); - VolumeControlStateMachine VolumeControlSm = - new VolumeControlStateMachine(device, svc, nativeInterface, looper); - VolumeControlSm.start(); - return VolumeControlSm; - } - public void doQuit() { log("doQuit for device " + mDevice); quitNow(); } - public void cleanup() { - log("cleanup for device " + mDevice); - } - @VisibleForTesting class Disconnected extends State { @Override @@ -116,11 +102,11 @@ public class VolumeControlStateMachine extends StateMachine { + "): " + messageWhatToString(getCurrentMessage().what)); - removeDeferredMessages(DISCONNECT); + removeDeferredMessages(MESSAGE_DISCONNECT); if (mLastConnectionState != -1) { // Don't broadcast during startup - broadcastConnectionState(BluetoothProfile.STATE_DISCONNECTED, mLastConnectionState); + broadcastConnectionState(STATE_DISCONNECTED, mLastConnectionState); } } @@ -131,7 +117,7 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_DISCONNECTED; + mLastConnectionState = STATE_DISCONNECTED; } @Override @@ -143,7 +129,7 @@ public class VolumeControlStateMachine extends StateMachine { + messageWhatToString(message.what)); switch (message.what) { - case CONNECT: + case MESSAGE_CONNECT -> { log("Connecting to " + mDevice); if (!mNativeInterface.connectVolumeControl(mDevice)) { Log.e(TAG, "Disconnected: error connecting to " + mDevice); @@ -157,27 +143,26 @@ public class VolumeControlStateMachine extends StateMachine { TAG, "Outgoing VolumeControl Connecting request rejected: " + mDevice); } - break; - case DISCONNECT: + } + case MESSAGE_DISCONNECT -> { Log.w(TAG, "Disconnected: DISCONNECT ignored: " + mDevice); - break; - case STACK_EVENT: + } + case MESSAGE_STACK_EVENT -> { VolumeControlStackEvent event = (VolumeControlStackEvent) message.obj; Log.d(TAG, "Disconnected: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); } switch (event.type) { - case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: + case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED -> { processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Disconnected: ignoring stack event: " + event); - break; + } + default -> Log.e(TAG, "Disconnected: ignoring stack event: " + event); } - break; - default: + } + default -> { return NOT_HANDLED; + } } return HANDLED; } @@ -185,10 +170,7 @@ public class VolumeControlStateMachine extends StateMachine { // in Disconnected state private void processConnectionEvent(int state) { switch (state) { - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED: - Log.w(TAG, "Ignore VolumeControl DISCONNECTED event: " + mDevice); - break; - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTING: + case STATE_CONNECTING -> { if (mService.okToConnect(mDevice)) { Log.i( TAG, @@ -201,8 +183,8 @@ public class VolumeControlStateMachine extends StateMachine { "Incoming Volume Control Connecting request rejected: " + mDevice); mNativeInterface.disconnectVolumeControl(mDevice); } - break; - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTED: + } + case STATE_CONNECTED -> { Log.w(TAG, "VolumeControl Connected from Disconnected state: " + mDevice); if (mService.okToConnect(mDevice)) { Log.i( @@ -214,13 +196,8 @@ public class VolumeControlStateMachine extends StateMachine { Log.w(TAG, "Incoming VolumeControl Connected request rejected: " + mDevice); mNativeInterface.disconnectVolumeControl(mDevice); } - break; - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTING: - Log.w(TAG, "Ignore VolumeControl DISCONNECTING event: " + mDevice); - break; - default: - Log.e(TAG, "Incorrect state: " + state + " device: " + mDevice); - break; + } + default -> Log.e(TAG, "Incorrect state: " + state + " device: " + mDevice); } } } @@ -235,8 +212,8 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); - broadcastConnectionState(BluetoothProfile.STATE_CONNECTING, mLastConnectionState); + sendMessageDelayed(MESSAGE_CONNECT_TIMEOUT, CONNECT_TIMEOUT.toMillis()); + broadcastConnectionState(STATE_CONNECTING, mLastConnectionState); } @Override @@ -246,8 +223,8 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_CONNECTING; - removeMessages(CONNECT_TIMEOUT); + mLastConnectionState = STATE_CONNECTING; + removeMessages(MESSAGE_CONNECT_TIMEOUT); } @Override @@ -259,42 +236,38 @@ public class VolumeControlStateMachine extends StateMachine { + messageWhatToString(message.what)); switch (message.what) { - case CONNECT: - deferMessage(message); - break; - case CONNECT_TIMEOUT: + case MESSAGE_CONNECT -> deferMessage(message); + case MESSAGE_CONNECT_TIMEOUT -> { Log.w(TAG, "Connecting connection timeout: " + mDevice); mNativeInterface.disconnectVolumeControl(mDevice); VolumeControlStackEvent disconnectEvent = new VolumeControlStackEvent( VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); disconnectEvent.device = mDevice; - disconnectEvent.valueInt1 = - VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED; - sendMessage(STACK_EVENT, disconnectEvent); - break; - case DISCONNECT: + disconnectEvent.valueInt1 = STATE_DISCONNECTED; + sendMessage(MESSAGE_STACK_EVENT, disconnectEvent); + } + case MESSAGE_DISCONNECT -> { log("Connecting: connection canceled to " + mDevice); mNativeInterface.disconnectVolumeControl(mDevice); transitionTo(mDisconnected); - break; - case STACK_EVENT: + } + case MESSAGE_STACK_EVENT -> { VolumeControlStackEvent event = (VolumeControlStackEvent) message.obj; log("Connecting: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); } switch (event.type) { - case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: + case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED -> { processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Connecting: ignoring stack event: " + event); - break; + } + default -> Log.e(TAG, "Connecting: ignoring stack event: " + event); } - break; - default: + } + default -> { return NOT_HANDLED; + } } return HANDLED; } @@ -302,41 +275,29 @@ public class VolumeControlStateMachine extends StateMachine { // in Connecting state private void processConnectionEvent(int state) { switch (state) { - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED: + case STATE_DISCONNECTED -> { Log.w(TAG, "Connecting device disconnected: " + mDevice); transitionTo(mDisconnected); - break; - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTED: - transitionTo(mConnected); - break; - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTING: - break; - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTING: + } + case STATE_CONNECTED -> transitionTo(mConnected); + case STATE_DISCONNECTING -> { Log.w(TAG, "Connecting interrupted: device is disconnecting: " + mDevice); transitionTo(mDisconnecting); - break; - default: - Log.e(TAG, "Incorrect state: " + state); - break; + } + default -> Log.e(TAG, "Incorrect state: " + state); } } } int getConnectionState() { String currentState = getCurrentState().getName(); - switch (currentState) { - case "Disconnected": - return BluetoothProfile.STATE_DISCONNECTED; - case "Connecting": - return BluetoothProfile.STATE_CONNECTING; - case "Connected": - return BluetoothProfile.STATE_CONNECTED; - case "Disconnecting": - return BluetoothProfile.STATE_DISCONNECTING; - default: - Log.e(TAG, "Bad currentState: " + currentState); - return BluetoothProfile.STATE_DISCONNECTED; - } + return switch (currentState) { + case "Disconnected" -> STATE_DISCONNECTED; + case "Connecting" -> STATE_CONNECTING; + case "Connected" -> STATE_CONNECTED; + case "Disconnecting" -> STATE_DISCONNECTING; + default -> STATE_DISCONNECTED; + }; } @VisibleForTesting @@ -349,8 +310,8 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); - broadcastConnectionState(BluetoothProfile.STATE_DISCONNECTING, mLastConnectionState); + sendMessageDelayed(MESSAGE_CONNECT_TIMEOUT, CONNECT_TIMEOUT.toMillis()); + broadcastConnectionState(STATE_DISCONNECTING, mLastConnectionState); } @Override @@ -360,8 +321,8 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_DISCONNECTING; - removeMessages(CONNECT_TIMEOUT); + mLastConnectionState = STATE_DISCONNECTING; + removeMessages(MESSAGE_CONNECT_TIMEOUT); } @Override @@ -373,43 +334,33 @@ public class VolumeControlStateMachine extends StateMachine { + messageWhatToString(message.what)); switch (message.what) { - case CONNECT: - deferMessage(message); - break; - case CONNECT_TIMEOUT: - { - Log.w(TAG, "Disconnecting connection timeout: " + mDevice); - mNativeInterface.disconnectVolumeControl(mDevice); - VolumeControlStackEvent disconnectEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent - .EVENT_TYPE_CONNECTION_STATE_CHANGED); - disconnectEvent.device = mDevice; - disconnectEvent.valueInt1 = - VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED; - sendMessage(STACK_EVENT, disconnectEvent); - break; - } - case DISCONNECT: - deferMessage(message); - break; - case STACK_EVENT: + case MESSAGE_CONNECT, MESSAGE_DISCONNECT -> deferMessage(message); + case MESSAGE_CONNECT_TIMEOUT -> { + Log.w(TAG, "Disconnecting connection timeout: " + mDevice); + mNativeInterface.disconnectVolumeControl(mDevice); + VolumeControlStackEvent disconnectEvent = + new VolumeControlStackEvent( + VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); + disconnectEvent.device = mDevice; + disconnectEvent.valueInt1 = STATE_DISCONNECTED; + sendMessage(MESSAGE_STACK_EVENT, disconnectEvent); + } + case MESSAGE_STACK_EVENT -> { VolumeControlStackEvent event = (VolumeControlStackEvent) message.obj; log("Disconnecting: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); } switch (event.type) { - case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: + case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED -> { processConnectionEvent(event.valueInt1); - break; - default: - Log.e(TAG, "Disconnecting: ignoring stack event: " + event); - break; + } + default -> Log.e(TAG, "Disconnecting: ignoring stack event: " + event); } - break; - default: + } + default -> { return NOT_HANDLED; + } } return HANDLED; } @@ -417,11 +368,11 @@ public class VolumeControlStateMachine extends StateMachine { // in Disconnecting state private void processConnectionEvent(int state) { switch (state) { - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED: + case STATE_DISCONNECTED -> { Log.i(TAG, "Disconnected: " + mDevice); transitionTo(mDisconnected); - break; - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTED: + } + case STATE_CONNECTED -> { if (mService.okToConnect(mDevice)) { Log.w(TAG, "Disconnecting interrupted: device is connected: " + mDevice); transitionTo(mConnected); @@ -430,8 +381,8 @@ public class VolumeControlStateMachine extends StateMachine { Log.w(TAG, "Incoming VolumeControl Connected request rejected: " + mDevice); mNativeInterface.disconnectVolumeControl(mDevice); } - break; - case VolumeControlStackEvent.CONNECTION_STATE_CONNECTING: + } + case STATE_CONNECTING -> { if (mService.okToConnect(mDevice)) { Log.i(TAG, "Disconnecting interrupted: try to reconnect: " + mDevice); transitionTo(mConnecting); @@ -442,12 +393,8 @@ public class VolumeControlStateMachine extends StateMachine { "Incoming VolumeControl Connecting request rejected: " + mDevice); mNativeInterface.disconnectVolumeControl(mDevice); } - break; - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTING: - break; - default: - Log.e(TAG, "Incorrect state: " + state); - break; + } + default -> Log.e(TAG, "Incorrect state: " + state); } } } @@ -462,8 +409,8 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - removeDeferredMessages(CONNECT); - broadcastConnectionState(BluetoothProfile.STATE_CONNECTED, mLastConnectionState); + removeDeferredMessages(MESSAGE_CONNECT); + broadcastConnectionState(STATE_CONNECTED, mLastConnectionState); } @Override @@ -473,7 +420,7 @@ public class VolumeControlStateMachine extends StateMachine { + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); - mLastConnectionState = BluetoothProfile.STATE_CONNECTED; + mLastConnectionState = STATE_CONNECTED; } @Override @@ -481,10 +428,10 @@ public class VolumeControlStateMachine extends StateMachine { log("Connected process message(" + mDevice + "): " + messageWhatToString(message.what)); switch (message.what) { - case CONNECT: + case MESSAGE_CONNECT -> { Log.w(TAG, "Connected: CONNECT ignored: " + mDevice); - break; - case DISCONNECT: + } + case MESSAGE_DISCONNECT -> { log("Disconnecting from " + mDevice); if (!mNativeInterface.disconnectVolumeControl(mDevice)) { // If error in the native stack, transition directly to Disconnected state. @@ -493,24 +440,25 @@ public class VolumeControlStateMachine extends StateMachine { break; } transitionTo(mDisconnecting); - break; - case STACK_EVENT: + } + case MESSAGE_STACK_EVENT -> { VolumeControlStackEvent event = (VolumeControlStackEvent) message.obj; log("Connected: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event); } switch (event.type) { - case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: + case VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED -> { processConnectionEvent(event.valueInt1); - break; - default: + } + default -> { Log.e(TAG, "Connected: ignoring stack event: " + event); - break; + } } - break; - default: + } + default -> { return NOT_HANDLED; + } } return HANDLED; } @@ -518,17 +466,16 @@ public class VolumeControlStateMachine extends StateMachine { // in Connected state private void processConnectionEvent(int state) { switch (state) { - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED: + case STATE_DISCONNECTED -> { Log.i(TAG, "Disconnected from " + mDevice); transitionTo(mDisconnected); - break; - case VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTING: + } + case STATE_DISCONNECTING -> { Log.i(TAG, "Disconnecting from " + mDevice); transitionTo(mDisconnecting); - break; - default: - Log.e(TAG, "Connection State Device: " + mDevice + " bad state: " + state); - break; + } + default -> + Log.e(TAG, "Connection State Device: " + mDevice + " bad state: " + state); } } } @@ -547,9 +494,9 @@ public class VolumeControlStateMachine extends StateMachine { "Connection state " + mDevice + ": " - + profileStateToString(prevState) + + getConnectionStateName(prevState) + "->" - + profileStateToString(newState)); + + getConnectionStateName(newState)); mService.handleConnectionStateChanged(mDevice, prevState, newState); Intent intent = new Intent(BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED); @@ -563,35 +510,13 @@ public class VolumeControlStateMachine extends StateMachine { } private static String messageWhatToString(int what) { - switch (what) { - case CONNECT: - return "CONNECT"; - case DISCONNECT: - return "DISCONNECT"; - case STACK_EVENT: - return "STACK_EVENT"; - case CONNECT_TIMEOUT: - return "CONNECT_TIMEOUT"; - default: - break; - } - return Integer.toString(what); - } - - private static String profileStateToString(int state) { - switch (state) { - case BluetoothProfile.STATE_DISCONNECTED: - return "DISCONNECTED"; - case BluetoothProfile.STATE_CONNECTING: - return "CONNECTING"; - case BluetoothProfile.STATE_CONNECTED: - return "CONNECTED"; - case BluetoothProfile.STATE_DISCONNECTING: - return "DISCONNECTING"; - default: - break; - } - return Integer.toString(state); + return switch (what) { + case MESSAGE_CONNECT -> "CONNECT"; + case MESSAGE_DISCONNECT -> "DISCONNECT"; + case MESSAGE_STACK_EVENT -> "STACK_EVENT"; + case MESSAGE_CONNECT_TIMEOUT -> "CONNECT_TIMEOUT"; + default -> Integer.toString(what); + }; } public void dump(StringBuilder sb) { @@ -611,9 +536,4 @@ public class VolumeControlStateMachine extends StateMachine { } scanner.close(); } - - @Override - protected void log(String msg) { - super.log(msg); - } } diff --git a/android/app/tests/unit/Android.bp b/android/app/tests/unit/Android.bp index e65bf03f65..979650019d 100644 --- a/android/app/tests/unit/Android.bp +++ b/android/app/tests/unit/Android.bp @@ -41,6 +41,7 @@ java_defaults { "truth", ], + jarjar_rules: ":bluetooth-jarjar-rules", asset_dirs: ["src/com/android/bluetooth/btservice/storage/schemas"], // Include all test java files. 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 ac848668af..12a0f7d9ef 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 @@ -62,6 +62,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Binder; +import android.os.Handler; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -784,7 +785,8 @@ public class BassClientServiceTest { @Test @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE) - public void testNotRemovingCachedBroadcastOnLostWithoutScanning() { + @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) + public void testNotRemovingCachedBroadcastOnLostWithoutScanning_noResyncFlag() { prepareConnectedDeviceGroup(); startSearchingForSources(); @@ -814,7 +816,47 @@ public class BassClientServiceTest { throw e.rethrowFromSystemServer(); } - // Scan and sync again + // Add broadcast to cache + onScanResult(mSourceDevice, TEST_BROADCAST_ID); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + + // Stop searching + mBassClientService.stopSearchingForSources(); + + // Add sync handle by add source + mBassClientService.addSource(mCurrentDevice, meta, true); + handleHandoverSupport(); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); + + // Sync lost without active scanning should not remove broadcast cache + onSyncLost(); + + // Add source to unsynced broadcast, causes synchronization first + mBassClientService.addSource(mCurrentDevice, meta, true); + handleHandoverSupport(); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + } + + @Test + @EnableFlags({ + Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE, + Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER + }) + public void testNotRemovingCachedBroadcastOnLostWithoutScanning() { + prepareConnectedDeviceGroup(); + startSearchingForSources(); + + // Scan and sync 1 onScanResult(mSourceDevice, TEST_BROADCAST_ID); mInOrderMethodProxy .verify(mMethodProxy) @@ -822,11 +864,47 @@ public class BassClientServiceTest { any(), any(), anyInt(), anyInt(), any(), any()); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); + // Sync lost during scanning removes cached broadcast + onSyncLost(); + checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); + + // Add source to not cached broadcast cause addFailed notification + BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); + mBassClientService.addSource(mCurrentDevice, meta, true); + handleHandoverSupport(); + TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); + try { + verify(mCallback) + .onSourceAddFailed( + eq(mCurrentDevice), + eq(meta), + eq(BluetoothStatusCodes.ERROR_BAD_PARAMETERS)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + // Add broadcast to cache + onScanResult(mSourceDevice, TEST_BROADCAST_ID); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + // Stop searching mBassClientService.stopSearchingForSources(); + // Add sync handle by add source + mBassClientService.addSource(mCurrentDevice, meta, true); + handleHandoverSupport(); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); + // Sync lost without active scanning should not remove broadcast cache onSyncLost(); + checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); // Add source to unsynced broadcast, causes synchronization first mBassClientService.addSource(mCurrentDevice, meta, true); @@ -1115,20 +1193,20 @@ public class BassClientServiceTest { any(), any(), anyInt(), anyInt(), any(), any()); } - private void checkNoMessage(int message) { - assertThat(mBassClientService.mHandler.hasMessages(message)).isFalse(); + private void checkNoTimeout(int broadcastId, int message) { + assertThat(mBassClientService.mTimeoutHandler.isStarted(broadcastId, message)).isFalse(); } - private void checkMessage(int message) { - assertThat(mBassClientService.mHandler.hasMessages(message)).isTrue(); + private void checkTimeout(int broadcastId, int message) { + assertThat(mBassClientService.mTimeoutHandler.isStarted(broadcastId, message)).isTrue(); } - private void checkAndDispatchMessage(int message, int broadcastId) { - checkMessage(message); - mBassClientService.mHandler.removeMessages(message); - Message newMsg = mBassClientService.mHandler.obtainMessage(message); - newMsg.arg1 = broadcastId; - mBassClientService.mHandler.dispatchMessage(newMsg); + private void checkAndDispatchTimeout(int broadcastId, int message) { + checkTimeout(broadcastId, message); + mBassClientService.mTimeoutHandler.stop(broadcastId, message); + Handler handler = mBassClientService.mTimeoutHandler.getOrCreateHandler(broadcastId); + Message newMsg = handler.obtainMessage(message); + handler.dispatchMessage(newMsg); } @Test @@ -1154,7 +1232,8 @@ public class BassClientServiceTest { handleHandoverSupport(); // Source synced which cause start timeout event - checkNoMessage(BassClientService.MESSAGE_SYNC_TIMEOUT); + assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) + .isFalse(); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); @@ -1163,7 +1242,13 @@ public class BassClientServiceTest { assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) .isEqualTo(TEST_BROADCAST_ID); - checkAndDispatchMessage(BassClientService.MESSAGE_SYNC_TIMEOUT, TEST_BROADCAST_ID); + assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) + .isTrue(); + mBassClientService.mHandler.removeMessages(BassClientService.MESSAGE_SYNC_TIMEOUT); + Message newMsg = + mBassClientService.mHandler.obtainMessage(BassClientService.MESSAGE_SYNC_TIMEOUT); + newMsg.arg1 = TEST_BROADCAST_ID; + mBassClientService.mHandler.dispatchMessage(newMsg); // Check if unsyced mInOrderMethodProxy @@ -1194,9 +1279,11 @@ public class BassClientServiceTest { handleHandoverSupport(); // Source synced which cause start timeout event - checkNoMessage(BassClientService.MESSAGE_SYNC_TIMEOUT); + assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) + .isFalse(); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); - checkMessage(BassClientService.MESSAGE_SYNC_TIMEOUT); + assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) + .isTrue(); assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) @@ -1206,7 +1293,8 @@ public class BassClientServiceTest { // Start searching again should clear timeout startSearchingForSources(); - checkNoMessage(BassClientService.MESSAGE_SYNC_TIMEOUT); + assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) + .isFalse(); mInOrderMethodProxy .verify(mMethodProxy, never()) @@ -1549,6 +1637,38 @@ public class BassClientServiceTest { } } + private void injectRemoteSourceStateChanged( + BluetoothLeBroadcastMetadata meta, int paSynState, boolean isBisSynced) { + for (BassClientStateMachine sm : mStateMachines.values()) { + // Update receiver state + if (sm.getDevice().equals(mCurrentDevice)) { + injectRemoteSourceStateChanged( + sm, + meta, + TEST_SOURCE_ID, + paSynState, + meta.isEncrypted() + ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING + : BluetoothLeBroadcastReceiveState + .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, + null, + isBisSynced ? (long) 0x00000001 : (long) 0x00000000); + } else if (sm.getDevice().equals(mCurrentDevice1)) { + injectRemoteSourceStateChanged( + sm, + meta, + TEST_SOURCE_ID + 1, + paSynState, + meta.isEncrypted() + ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING + : BluetoothLeBroadcastReceiveState + .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, + null, + isBisSynced ? (long) 0x00000002 : (long) 0x00000000); + } + } + } + private void injectRemoteSourceStateRemoval(BassClientStateMachine sm, int sourceId) { List<BluetoothLeBroadcastReceiveState> stateList = sm.getAllSources(); if (stateList == null) { @@ -3155,11 +3275,11 @@ public class BassClientServiceTest { mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerUnregisterSync(any(), any()); - onSyncEstablished(device5, handle5); mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); + onSyncEstablished(device5, handle5); assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(4); assertThat(mBassClientService.getActiveSyncedSources()) .containsExactly(handle2, handle3, handle4, handle5) @@ -4127,8 +4247,8 @@ public class BassClientServiceTest { verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); Mockito.clearInvocations(mLeAudioService); - /* Imitate broadcast source stop, sink notify about loosing BIS sync */ - injectRemoteSourceStateChanged(meta, true, false); + /* Imitate broadcast source stop, sink notify about loosing PA and BIS sync */ + injectRemoteSourceStateChanged(meta, false, false); /* Unicast would like to stream */ mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); @@ -4165,8 +4285,8 @@ public class BassClientServiceTest { 0 /* STATUS_LOCAL_STREAM_REQUESTED */); if (Flags.leaudioBroadcastAssistantPeripheralEntrustment()) { - /* Imitate broadcast source stop, sink notify about loosing BIS sync */ - injectRemoteSourceStateChanged(meta, true, false); + /* Imitate broadcast source stop, sink notify about loosing PA and BIS sync */ + injectRemoteSourceStateChanged(meta, false, false); } else { verifyRemoveMessageAndInjectSourceRemoval(); } @@ -5351,6 +5471,51 @@ public class BassClientServiceTest { @Test @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE) + @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) + public void onSyncLost_notifySourceLostAndCancelSync_noResyncFlag() { + prepareConnectedDeviceGroup(); + startSearchingForSources(); + onScanResult(mSourceDevice, TEST_BROADCAST_ID); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); + assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); + assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); + assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) + .isEqualTo(mSourceDevice); + assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) + .isEqualTo(TEST_BROADCAST_ID); + + onSyncLost(); + + TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); + try { + verify(mCallback).onSourceLost(eq(TEST_BROADCAST_ID)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + // Cleaned all + assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); + assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isEqualTo(null); + assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) + .isEqualTo(BassConstants.INVALID_BROADCAST_ID); + + // Could try to sync again + onScanResult(mSourceDevice, TEST_BROADCAST_ID); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + } + + @Test + @EnableFlags({ + Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE, + Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER + }) public void onSyncLost_notifySourceLostAndCancelSync() { prepareConnectedDeviceGroup(); startSearchingForSources(); @@ -5368,6 +5533,7 @@ public class BassClientServiceTest { .isEqualTo(TEST_BROADCAST_ID); onSyncLost(); + checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); try { @@ -5390,6 +5556,92 @@ public class BassClientServiceTest { any(), any(), anyInt(), anyInt(), any(), any()); } + @Test + @EnableFlags({ + Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE, + Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER + }) + public void monitorBroadcastAfterSyncMaxLimit() { + final BluetoothDevice device1 = + mBluetoothAdapter.getRemoteLeDevice( + "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); + final BluetoothDevice device2 = + mBluetoothAdapter.getRemoteLeDevice( + "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); + final BluetoothDevice device3 = + mBluetoothAdapter.getRemoteLeDevice( + "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); + final BluetoothDevice device4 = + mBluetoothAdapter.getRemoteLeDevice( + "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); + final BluetoothDevice device5 = + mBluetoothAdapter.getRemoteLeDevice( + "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); + final int handle1 = 0; + final int handle2 = 1; + final int handle3 = 2; + final int handle4 = 3; + final int handle5 = 4; + final int broadcastId1 = 1111; + final int broadcastId2 = 2222; + final int broadcastId3 = 3333; + final int broadcastId4 = 4444; + final int broadcastId5 = 5555; + + prepareConnectedDeviceGroup(); + startSearchingForSources(); + + // Scan and sync 5 sources cause removing 1 synced element + onScanResult(device1, broadcastId1); + onSyncEstablished(device1, handle1); + onScanResult(device2, broadcastId2); + onSyncEstablished(device2, handle2); + onScanResult(device3, broadcastId3); + onSyncEstablished(device3, handle3); + onScanResult(device4, broadcastId4); + onSyncEstablished(device4, handle4); + onScanResult(device5, broadcastId5); + mInOrderMethodProxy + .verify(mMethodProxy, times(4)) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerUnregisterSync(any(), any()); + + checkTimeout(broadcastId1, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); + + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + onSyncEstablished(device5, handle5); + + // Couldn't sync again as broadcast is in the cache + onScanResult(device1, broadcastId1); + mInOrderMethodProxy + .verify(mMethodProxy, never()) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + + // Lost should notify about lost and clear cache + checkAndDispatchTimeout(broadcastId1, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); + + TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); + try { + verify(mCallback).onSourceLost(eq(broadcastId1)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + // Could try to sync again + onScanResult(device1, broadcastId1); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + } + private void prepareSynchronizedPair() { prepareConnectedDeviceGroup(); startSearchingForSources(); @@ -5432,7 +5684,7 @@ public class BassClientServiceTest { .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); } private void sinkUnintentionalDuringScanning() { @@ -5441,7 +5693,7 @@ public class BassClientServiceTest { // Bis and PA unsynced, SINK_UNINTENTIONAL BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); injectRemoteSourceStateChanged(meta, false, false); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); } private void checkResumeSynchronizationByBig() { @@ -5491,16 +5743,16 @@ public class BassClientServiceTest { } private void verifyStopBigMonitoringWithUnsync() { - checkNoMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerUnregisterSync(any(), any()); } private void verifyStopBigMonitoringWithoutUnsync() { - checkNoMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); mInOrderMethodProxy .verify(mMethodProxy, never()) .periodicAdvertisingManagerUnregisterSync(any(), any()); @@ -5527,14 +5779,14 @@ public class BassClientServiceTest { .verify(mMethodProxy, never()) .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); - checkNoMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); } private void checkSinkPause() { BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); injectRemoteSourceStateChanged(meta, false, false); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); } @Test @@ -5807,7 +6059,7 @@ public class BassClientServiceTest { (long) 0x00000000); } } - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); // Unsync all sinks cause stop monitoring for (BassClientStateMachine sm : mStateMachines.values()) { @@ -5849,7 +6101,7 @@ public class BassClientServiceTest { (long) 0x00000000); } } - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); // Unsync all sinks cause stop monitoring for (BassClientStateMachine sm : mStateMachines.values()) { @@ -5886,7 +6138,7 @@ public class BassClientServiceTest { mCurrentDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); // Disconnect all sinks cause stop monitoring doReturn(BluetoothProfile.STATE_DISCONNECTED) @@ -5918,7 +6170,7 @@ public class BassClientServiceTest { mCurrentDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); // Disconnect all sinks cause stop monitoring doReturn(BluetoothProfile.STATE_DISCONNECTED) @@ -5941,10 +6193,10 @@ public class BassClientServiceTest { public void sinkUnintentional_syncLost_withoutScanning_outOfRange() { sinkUnintentionalWithoutScanning(); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); onSyncLost(); - checkMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( @@ -5956,8 +6208,8 @@ public class BassClientServiceTest { .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); - checkAndDispatchMessage( - BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT, TEST_BROADCAST_ID); + checkAndDispatchTimeout( + TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); verifyStopBigMonitoringWithUnsync(); verifyRemoveMessageAndInjectSourceRemoval(); checkNoResumeSynchronizationByBig(); @@ -5971,10 +6223,10 @@ public class BassClientServiceTest { public void sinkUnintentional_syncLost_duringScanning_outOfRange() { sinkUnintentionalDuringScanning(); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); onSyncLost(); - checkMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( @@ -5986,8 +6238,8 @@ public class BassClientServiceTest { .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); - checkAndDispatchMessage( - BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT, TEST_BROADCAST_ID); + checkAndDispatchTimeout( + TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); verifyStopBigMonitoringWithoutUnsync(); verifyRemoveMessageAndInjectSourceRemoval(); checkNoResumeSynchronizationByBig(); @@ -6001,7 +6253,7 @@ public class BassClientServiceTest { public void sinkUnintentional_bigMonitorTimeout_withoutScanning() { sinkUnintentionalWithoutScanning(); - checkAndDispatchMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT, TEST_BROADCAST_ID); + checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); verifyStopBigMonitoringWithUnsync(); verifyRemoveMessageAndInjectSourceRemoval(); checkNoResumeSynchronizationByBig(); @@ -6015,7 +6267,7 @@ public class BassClientServiceTest { public void sinkUnintentional_bigMonitorTimeout_duringScanning() { sinkUnintentionalDuringScanning(); - checkAndDispatchMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT, TEST_BROADCAST_ID); + checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); verifyStopBigMonitoringWithoutUnsync(); verifyRemoveMessageAndInjectSourceRemoval(); checkNoResumeSynchronizationByBig(); @@ -6371,11 +6623,11 @@ public class BassClientServiceTest { .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); - checkMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( @@ -6387,8 +6639,8 @@ public class BassClientServiceTest { .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); - checkAndDispatchMessage( - BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT, TEST_BROADCAST_ID); + checkAndDispatchTimeout( + TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); verifyStopBigMonitoringWithUnsync(); } @@ -6407,11 +6659,11 @@ public class BassClientServiceTest { .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( any(), any(), anyInt(), anyInt(), any(), any()); - checkMessage(BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); - checkMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); mInOrderMethodProxy .verify(mMethodProxy) .periodicAdvertisingManagerRegisterSync( @@ -6424,7 +6676,7 @@ public class BassClientServiceTest { any(), any(), anyInt(), anyInt(), any(), any()); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); - checkNoMessage(BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); + checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); } @Test @@ -6537,4 +6789,145 @@ public class BassClientServiceTest { assertThat(mBassClientService.isLocalBroadcast(metadata)).isTrue(); assertThat(mBassClientService.isLocalBroadcast(receiveState)).isTrue(); } + + private void verifyInitiatePaSyncTransferAndNoOthers() { + expect.that(mStateMachines.size()).isEqualTo(2); + for (BassClientStateMachine sm : mStateMachines.values()) { + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); + long count; + if (sm.getDevice().equals(mCurrentDevice)) { + count = + messageCaptor.getAllValues().stream() + .filter( + m -> + (m.what + == BassClientStateMachine + .INITIATE_PA_SYNC_TRANSFER) + && (m.arg1 == TEST_SYNC_HANDLE) + && (m.arg2 == TEST_SOURCE_ID)) + .count(); + assertThat(count).isEqualTo(1); + count = + messageCaptor.getAllValues().stream() + .filter( + m -> + m.what + != BassClientStateMachine + .INITIATE_PA_SYNC_TRANSFER) + .count(); + assertThat(count).isEqualTo(0); + } else if (sm.getDevice().equals(mCurrentDevice1)) { + count = + messageCaptor.getAllValues().stream() + .filter( + m -> + (m.what + == BassClientStateMachine + .INITIATE_PA_SYNC_TRANSFER) + && (m.arg1 == TEST_SYNC_HANDLE) + && (m.arg2 == TEST_SOURCE_ID + 1)) + .count(); + assertThat(count).isEqualTo(1); + count = + messageCaptor.getAllValues().stream() + .filter( + m -> + m.what + != BassClientStateMachine + .INITIATE_PA_SYNC_TRANSFER) + .count(); + assertThat(count).isEqualTo(0); + } else { + throw new AssertionError("Unexpected device"); + } + } + } + + @Test + @EnableFlags({ + Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, + Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE + }) + public void initiatePaSyncTransfer() { + prepareSynchronizedPairAndStopSearching(); + + // Sync info request force syncing to broadcaster and add sinks pending for PAST + mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); + mBassClientService.syncRequestForPast( + mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + + // Sync will INITIATE_PA_SYNC_TRANSFER + onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); + verifyInitiatePaSyncTransferAndNoOthers(); + } + + @Test + @EnableFlags({ + Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, + Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE + }) + public void InitiatePaSyncTransfer_concurrentWithResume() { + prepareSynchronizedPairAndStopSearching(); + + BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); + + // Cache sinks for resume and set HOST_INTENTIONAL pause + mBassClientService.handleUnicastSourceStreamStatusChange( + 0 /* STATUS_LOCAL_STREAM_REQUESTED */); + injectRemoteSourceStateChanged(meta, false, false); + + // Resume source will force syncing to broadcaser and put pending source to add + mBassClientService.resumeReceiversSourceSynchronization(); + mInOrderMethodProxy + .verify(mMethodProxy) + .periodicAdvertisingManagerRegisterSync( + any(), any(), anyInt(), anyInt(), any(), any()); + + // Sync info request add sinks pending for PAST + mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); + mBassClientService.syncRequestForPast( + mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); + + // Sync will send INITIATE_PA_SYNC_TRANSFER and remove pending soure to add + onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); + verifyInitiatePaSyncTransferAndNoOthers(); + } + + @Test + @EnableFlags({ + Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, + Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE + }) + public void resumeSourceSynchronization_omitWhenPaSyncedOrRequested() { + prepareSynchronizedPair(); + + BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); + + // Cache sinks for resume and set HOST_INTENTIONAL pause + // Try resume while sync info requested + mBassClientService.handleUnicastSourceStreamStatusChange( + 0 /* STATUS_LOCAL_STREAM_REQUESTED */); + injectRemoteSourceStateChanged( + meta, BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCINFO_REQUEST, false); + checkNoResumeSynchronizationByHost(); + + // Cache sinks for resume and set HOST_INTENTIONAL pause + // Try resume while pa synced + mBassClientService.handleUnicastSourceStreamStatusChange( + 0 /* STATUS_LOCAL_STREAM_REQUESTED */); + injectRemoteSourceStateChanged(meta, true, false); + checkNoResumeSynchronizationByHost(); + + // Cache sinks for resume and set HOST_INTENTIONAL pause + // Try resume while pa unsynced + mBassClientService.handleUnicastSourceStreamStatusChange( + 0 /* STATUS_LOCAL_STREAM_REQUESTED */); + injectRemoteSourceStateChanged(meta, false, false); + checkResumeSynchronizationByHost(); + } } 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 e4ae0e4dd8..696526bb26 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 @@ -32,6 +32,7 @@ import static com.android.bluetooth.bass_client.BassClientStateMachine.CONNECT_T import static com.android.bluetooth.bass_client.BassClientStateMachine.DISCONNECT; import static com.android.bluetooth.bass_client.BassClientStateMachine.GATT_TXN_PROCESSED; import static com.android.bluetooth.bass_client.BassClientStateMachine.GATT_TXN_TIMEOUT; +import static com.android.bluetooth.bass_client.BassClientStateMachine.INITIATE_PA_SYNC_TRANSFER; import static com.android.bluetooth.bass_client.BassClientStateMachine.PSYNC_ACTIVE_TIMEOUT; import static com.android.bluetooth.bass_client.BassClientStateMachine.REACHED_MAX_SOURCE_LIMIT; import static com.android.bluetooth.bass_client.BassClientStateMachine.READ_BASS_CHARACTERISTICS; @@ -894,12 +895,23 @@ public class BassClientStateMachineTest { when(characteristic.getValue()).thenReturn(value); when(mBassClientService.getPeriodicAdvertisementResult(any(), anyInt())) .thenReturn(paResult); - when(paResult.getSyncHandle()).thenReturn(100); + int syncHandle = 100; + when(paResult.getSyncHandle()).thenReturn(syncHandle); Mockito.clearInvocations(callbacks); cb.onCharacteristicRead(null, characteristic, GATT_SUCCESS); TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); + 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)); + verify(callbacks) .notifyReceiveStateChanged(any(), eq(sourceId), receiveStateCaptor.capture()); Assert.assertEquals(receiveStateCaptor.getValue().getSourceDevice(), mSourceTestDevice); @@ -1707,6 +1719,26 @@ public class BassClientStateMachineTest { } @Test + public void sendInitiatePaSyncTransferMessage_inConnectedState() { + initToConnectedState(); + int syncHandle = 1234; + int sourceId = 4321; + + mBassClientStateMachine.sendMessage(INITIATE_PA_SYNC_TRANSFER, syncHandle, sourceId); + TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); + + 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)); + } + + @Test public void sendConnectMessage_inConnectedProcessingState_doesNotChangeState() { initToConnectedProcessingState(); @@ -1906,6 +1938,11 @@ public class BassClientStateMachineTest { mBassClientStateMachine.sendMessage(SWITCH_BCAST_SOURCE); TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); assertThat(mBassClientStateMachine.hasDeferredMessagesSuper(SWITCH_BCAST_SOURCE)).isTrue(); + + mBassClientStateMachine.sendMessage(INITIATE_PA_SYNC_TRANSFER); + TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); + assertThat(mBassClientStateMachine.hasDeferredMessagesSuper(INITIATE_PA_SYNC_TRANSFER)) + .isTrue(); } @Test 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 b50835e74a..541f965969 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 @@ -24,6 +24,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -67,6 +68,7 @@ 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.Mockito; import org.mockito.Spy; @@ -87,6 +89,7 @@ public class ActiveDeviceManagerTest { private BluetoothDevice mHearingAidDevice; private BluetoothDevice mLeAudioDevice; private BluetoothDevice mLeAudioDevice2; + private BluetoothDevice mLeAudioDevice3; private BluetoothDevice mLeHearingAidDevice; private BluetoothDevice mSecondaryAudioDevice; private BluetoothDevice mDualModeAudioDevice; @@ -146,6 +149,7 @@ public class ActiveDeviceManagerTest { mSecondaryAudioDevice = TestUtils.getTestDevice(mAdapter, 6); mDualModeAudioDevice = TestUtils.getTestDevice(mAdapter, 7); mLeAudioDevice2 = TestUtils.getTestDevice(mAdapter, 8); + mLeAudioDevice3 = TestUtils.getTestDevice(mAdapter, 9); mDeviceConnectionStack = new ArrayList<>(); mMostRecentDevice = null; mOriginalDualModeAudioState = Utils.isDualModeAudioEnabled(); @@ -161,6 +165,7 @@ public class ActiveDeviceManagerTest { when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice); when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice2); + when(mLeAudioService.getLeadDevice(mLeAudioDevice3)).thenReturn(mLeAudioDevice3); when(mLeAudioService.getLeadDevice(mDualModeAudioDevice)).thenReturn(mDualModeAudioDevice); when(mLeAudioService.getLeadDevice(mLeHearingAidDevice)).thenReturn(mLeHearingAidDevice); @@ -839,6 +844,161 @@ public class ActiveDeviceManagerTest { verify(mLeAudioService).setActiveDevice(mLeAudioDevice); } + /** + * One LE Audio set, containing two buds, is connected. When one device got disconnected + * fallback device should not be set to true active device to fallback device. + */ + @Test + @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER) + public void leAudioSecondDeviceDisconnected_noFallbackDeviceActive_ModeNormal() { + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); + + InOrder order = inOrder(mLeAudioService); + + int groupId = 1; + List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2); + when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice); + + leAudioConnected(mLeAudioDevice); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice); + + leAudioConnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(any()); + + when(mLeAudioService.getGroupId(any())).thenReturn(groupId); + when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices); + + leAudioDisconnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(any()); + } + + /** + * One LE Audio set, containing two buds, is connected. When one device got disconnected + * fallback device should not be set to true active device to fallback device. + */ + @Test + @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER) + public void leAudioSecondDeviceDisconnected_noFallbackDeviceActive_ModeInCall() { + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL); + + InOrder order = inOrder(mLeAudioService); + + int groupId = 1; + List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2); + when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice); + + leAudioConnected(mLeAudioDevice); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice); + + leAudioConnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(any()); + + when(mLeAudioService.getGroupId(any())).thenReturn(groupId); + when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices); + + leAudioDisconnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(any()); + } + + /** + * One LE Audio set, containing two buds, is connected. When one device got disconnected + * fallback device should not be set to true active device to fallback device. + */ + @Test + @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER) + public void twoLeAudioSets_OneSetDisconnected_FallbackToAnotherOne_ModeNormal() { + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); + + InOrder order = inOrder(mLeAudioService); + + int groupId = 1; + List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2); + + when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice); + when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(groupId); + when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(groupId); + when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices); + + int groupId2 = 2; + List<BluetoothDevice> groupDevicesId2 = List.of(mLeAudioDevice3); + + when(mLeAudioService.getGroupId(mLeAudioDevice3)).thenReturn(groupId2); + when(mLeAudioService.getGroupDevices(groupId2)).thenReturn(groupDevicesId2); + + leAudioConnected(mLeAudioDevice3); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice3); + + leAudioConnected(mLeAudioDevice); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice); + + leAudioConnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice2); + + leAudioDisconnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + // Should not encrease a number of this call. + order.verify(mLeAudioService, never()).setActiveDevice(any()); + + leAudioDisconnected(mLeAudioDevice); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice3); + } + + /** + * One LE Audio set, containing two buds, is connected. When one device got disconnected + * fallback device should not be set to true active device to fallback device. + */ + @Test + @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER) + public void twoLeAudioSets_OneSetDisconnected_FallbackToAnotherOne_ModeInCall() { + when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_IN_CALL); + + InOrder order = inOrder(mLeAudioService); + + int groupId = 1; + List<BluetoothDevice> groupDevices = List.of(mLeAudioDevice, mLeAudioDevice2); + + when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice); + when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(groupId); + when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(groupId); + when(mLeAudioService.getGroupDevices(groupId)).thenReturn(groupDevices); + + int groupId2 = 2; + List<BluetoothDevice> groupDevicesId2 = List.of(mLeAudioDevice3); + + when(mLeAudioService.getGroupId(mLeAudioDevice3)).thenReturn(groupId2); + when(mLeAudioService.getGroupDevices(groupId2)).thenReturn(groupDevicesId2); + + leAudioConnected(mLeAudioDevice3); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice3); + + leAudioConnected(mLeAudioDevice); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice); + + leAudioConnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(any()); + + leAudioDisconnected(mLeAudioDevice2); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, never()).setActiveDevice(any()); + + leAudioDisconnected(mLeAudioDevice); + mTestLooper.dispatchAll(); + order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice3); + } + /** A combo (A2DP + Headset) device is connected. Then an LE Audio is connected. */ @Test public void leAudioActive_clearA2dpAndHeadsetActive() { 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 7dadb2cc33..f73e0f064e 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 @@ -346,7 +346,6 @@ public class AdapterServiceTest { // Restores the foregroundUserId to the ID prior to the test setup Utils.setForegroundUserId(mForegroundUserId); - assertThat(mLooper.nextMessage()).isNull(); mAdapterService.cleanup(); mAdapterService.unregisterRemoteCallback(mIBluetoothCallback); AdapterNativeInterface.setInstance(null); @@ -567,6 +566,7 @@ public class AdapterServiceTest { @Test public void testEnable() { doEnable(false); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -580,6 +580,7 @@ public class AdapterServiceTest { verify(mNativeInterface).setScanMode(eq(halExpectedScanMode)); assertThat(mAdapterService.getScanMode()).isEqualTo(expectedScanMode); + assertThat(mLooper.nextMessage()).isNull(); } /** Test: Turn Bluetooth on/off. Check whether the AdapterService gets started and stopped. */ @@ -587,6 +588,7 @@ public class AdapterServiceTest { public void testEnableDisable() { doEnable(false); doDisable(false); + assertThat(mLooper.nextMessage()).isNull(); } /** @@ -613,6 +615,7 @@ public class AdapterServiceTest { Config.init(mockContext); doEnable(true); doDisable(true); + assertThat(mLooper.nextMessage()).isNull(); } /** Test: Don't start GATT Check whether the AdapterService quits gracefully */ @@ -646,6 +649,7 @@ public class AdapterServiceTest { verifyStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); + assertThat(mLooper.nextMessage()).isNull(); } /** Test: Don't stop GATT Check whether the AdapterService quits gracefully */ @@ -679,6 +683,7 @@ public class AdapterServiceTest { verifyStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -691,6 +696,7 @@ public class AdapterServiceTest { dropNextMessage(MESSAGE_PROFILE_SERVICE_REGISTERED); dropNextMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -700,6 +706,7 @@ public class AdapterServiceTest { assertThat(mAdapterService.getBluetoothGatt()).isNull(); assertThat(mAdapterService.getBluetoothScan()).isNotNull(); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -741,6 +748,7 @@ public class AdapterServiceTest { assertThat(mAdapterService.getBluetoothScan()).isNull(); assertThat(mAdapterService.getBluetoothGatt()).isNull(); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -808,6 +816,7 @@ public class AdapterServiceTest { assertThat(mAdapterService.getState()).isEqualTo(STATE_BLE_ON); mAdapterService.unregisterRemoteCallback(callback); + assertThat(mLooper.nextMessage()).isNull(); } /** Test: Don't start a classic profile Check whether the AdapterService quits gracefully */ @@ -851,6 +860,7 @@ public class AdapterServiceTest { // Ensure GATT is still running assertThat(mAdapterService.getBluetoothGatt()).isNotNull(); + assertThat(mLooper.nextMessage()).isNull(); } /** Test: Don't stop a classic profile Check whether the AdapterService quits gracefully */ @@ -885,6 +895,7 @@ public class AdapterServiceTest { verifyStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); + assertThat(mLooper.nextMessage()).isNull(); } /** Test: Toggle snoop logging setting Check whether the AdapterService restarts fully */ @@ -933,6 +944,7 @@ public class AdapterServiceTest { // Restore earlier setting BluetoothProperties.snoop_log_mode(snoopSetting); + assertThat(mLooper.nextMessage()).isNull(); } /** @@ -943,6 +955,7 @@ public class AdapterServiceTest { @Test public void testObfuscateBluetoothAddress_NullAddress() { assertThat(mAdapterService.obfuscateAddress(null)).isEmpty(); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -963,6 +976,7 @@ public class AdapterServiceTest { // Verify we can get correct identity address identityAddress = mAdapterService.getIdentityAddress(TEST_BT_ADDR_1); assertThat(identityAddress).isEqualTo(TEST_BT_ADDR_2); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -972,6 +986,7 @@ public class AdapterServiceTest { assertThat(mAdapterService.getByteIdentityAddress(device)).isNull(); assertThat(mAdapterService.getIdentityAddress(device.getAddress())).isNull(); + assertThat(mLooper.nextMessage()).isNull(); } public static byte[] getMetricsSalt(Map<String, Map<String, String>> adapterConfig) { @@ -1021,6 +1036,7 @@ public class AdapterServiceTest { @Test public void testGetMetricId_NullAddress() { assertThat(mAdapterService.getMetricId(null)).isEqualTo(0); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -1033,6 +1049,7 @@ public class AdapterServiceTest { doReturn(new byte[0]).when(mNativeInterface).dumpMetrics(); mAdapterService.dump(fd, writer, new String[] {"--proto-bin"}); mAdapterService.dump(fd, writer, new String[] {"random", "arguments"}); + assertThat(mLooper.nextMessage()).isNull(); } @Test @@ -1070,5 +1087,6 @@ public class AdapterServiceTest { Files.deleteIfExists(randomFileUnderBluedroidPath); Files.deleteIfExists(randomFileUnderBluetoothPath); } + assertThat(mLooper.nextMessage()).isNull(); } } 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 6129d25497..845a53b77c 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 @@ -17,6 +17,8 @@ import android.os.Bundle; import android.os.HandlerThread; import android.os.Message; import android.os.TestLooperManager; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; @@ -25,6 +27,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.Utils; import com.android.bluetooth.bas.BatteryService; import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; +import com.android.bluetooth.flags.Flags; import com.android.bluetooth.hfp.HeadsetHalConstants; import org.junit.After; @@ -55,6 +58,7 @@ public class RemoteDevicesTest { private Context mTargetContext; private BluetoothManager mBluetoothManager; + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); @@ -761,6 +765,18 @@ public class RemoteDevicesTest { } @Test + @EnableFlags(Flags.FLAG_FIX_ADD_DEVICE_PROPERTIES) + public void testMultipleAddDeviceProperties() { + // Verify that device property is null initially + Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); + DeviceProperties prop1 = + mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1)); + DeviceProperties prop2 = + mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1)); + Assert.assertEquals(prop2, prop1); + } + + @Test public void testSetgetHfAudioPolicyForRemoteAg() { // Verify that device property is null initially Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java index eb0e166a77..4195b96536 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java @@ -1770,7 +1770,6 @@ public class HeadsetServiceAndStateMachineTest { HeadsetCallState headsetCallState = new HeadsetCallState( 0, 0, HeadsetHalConstants.CALL_STATE_INCOMING, TEST_PHONE_NUMBER, 128, ""); - mTestLooper.startAutoDispatch(); // Require as this is waiting unconditionally mHeadsetService.phoneStateChanged( headsetCallState.mNumActive, headsetCallState.mNumHeld, @@ -1779,7 +1778,6 @@ public class HeadsetServiceAndStateMachineTest { headsetCallState.mType, headsetCallState.mName, false); - mTestLooper.stopAutoDispatch(); mTestLooper.dispatchAll(); // HeadsetStateMachine completes processing CALL_STATE_CHANGED message verify(mNativeInterface).phoneStateChange(device, headsetCallState); 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 309c7310d2..7261d369bf 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 @@ -31,8 +31,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.media.BluetoothProfileConnectionInfo; +import android.os.IBinder; import android.os.Looper; import android.os.ParcelUuid; +import android.os.RemoteException; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.MediumTest; @@ -96,6 +98,9 @@ public class LeAudioBroadcastServiceTest { @Mock private BassClientService mBassClientService; @Mock private TbsService mTbsService; @Mock private MetricsLogger mMetricsLogger; + @Mock private IBluetoothLeBroadcastCallback mCallbacks; + @Mock private IBinder mBinder; + @Spy private LeAudioObjectsFactory mObjectsFactory = LeAudioObjectsFactory.getInstance(); @Spy private ServiceFactory mServiceFactory = new ServiceFactory(); @@ -139,62 +144,13 @@ public class LeAudioBroadcastServiceTest { private static final List<BluetoothLeAudioCodecConfig> OUTPUT_SELECTABLE_CONFIG_HIGH = List.of(LC3_48KHZ_CONFIG); - private boolean mOnBroadcastStartedCalled = false; - private boolean mOnBroadcastStartFailedCalled = false; - private boolean mOnBroadcastStoppedCalled = false; - private boolean mOnBroadcastStopFailedCalled = false; - private boolean mOnBroadcastUpdatedCalled = false; - private boolean mOnBroadcastUpdateFailedCalled = false; - private int mOnBroadcastStartFailedReason = BluetoothStatusCodes.SUCCESS; - - private final IBluetoothLeBroadcastCallback mCallbacks = - new IBluetoothLeBroadcastCallback.Stub() { - @Override - public void onBroadcastStarted(int reason, int broadcastId) { - mOnBroadcastStartedCalled = true; - } - - @Override - public void onBroadcastStartFailed(int reason) { - mOnBroadcastStartFailedCalled = true; - mOnBroadcastStartFailedReason = reason; - } - - @Override - public void onBroadcastStopped(int reason, int broadcastId) { - mOnBroadcastStoppedCalled = true; - } - - @Override - public void onBroadcastStopFailed(int reason) { - mOnBroadcastStopFailedCalled = true; - } - - @Override - public void onPlaybackStarted(int reason, int broadcastId) {} - - @Override - public void onPlaybackStopped(int reason, int broadcastId) {} - - @Override - public void onBroadcastUpdated(int reason, int broadcastId) { - mOnBroadcastUpdatedCalled = true; - } - - @Override - public void onBroadcastUpdateFailed(int reason, int broadcastId) { - mOnBroadcastUpdateFailedCalled = true; - } - - @Override - public void onBroadcastMetadataChanged( - int broadcastId, BluetoothLeBroadcastMetadata metadata) {} - }; - @Before public void setUp() throws Exception { mTargetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + doReturn(mBinder).when(mCallbacks).asBinder(); + doNothing().when(mBinder).linkToDeath(any(), eq(0)); + // Use spied objects factory doNothing().when(mTmapGattServer).start(anyInt()); doNothing().when(mTmapGattServer).stop(); @@ -306,8 +262,10 @@ public class LeAudioBroadcastServiceTest { create_event.valueBool1 = true; mService.messageFromNative(create_event); - // Verify if broadcast is auto-started on start - verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); + if (!Flags.leaudioBigDependsOnAudioState()) { + // Verify if broadcast is auto-started on start + verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); + } // Notify initial paused state LeAudioStackEvent state_event = @@ -326,8 +284,14 @@ public class LeAudioBroadcastServiceTest { verify(mLeAudioBroadcasterNativeInterface).getBroadcastMetadata(eq(broadcastId)); TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); - Assert.assertFalse(mOnBroadcastStartFailedCalled); - Assert.assertTrue(mOnBroadcastStartedCalled); + try { + verify(mCallbacks, times(0)).onBroadcastStartFailed(anyInt()); + verify(mCallbacks, times(1)) + .onBroadcastStarted( + eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST), anyInt()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } void verifyBroadcastStopped(int broadcastId) { @@ -361,8 +325,14 @@ public class LeAudioBroadcastServiceTest { anyLong(), anyLong(), eq(0x3)); // STATS_SESSION_SETUP_STATUS_STREAMING - Assert.assertTrue(mOnBroadcastStoppedCalled); - Assert.assertFalse(mOnBroadcastStopFailedCalled); + try { + verify(mCallbacks, times(1)) + .onBroadcastStopped( + eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST), anyInt()); + verify(mCallbacks, times(0)).onBroadcastStopFailed(anyInt()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } @Test @@ -453,15 +423,19 @@ public class LeAudioBroadcastServiceTest { eq(0L), eq(0x4)); // STATS_SESSION_SETUP_STATUS_CREATED_FAILED - Assert.assertFalse(mOnBroadcastStartedCalled); - Assert.assertTrue(mOnBroadcastStartFailedCalled); + try { + verify(mCallbacks, times(0)).onBroadcastStarted(anyInt(), anyInt()); + verify(mCallbacks, times(1)) + .onBroadcastStartFailed(eq(BluetoothStatusCodes.ERROR_UNKNOWN)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } @Test public void testCreateBroadcastTimeout() { mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_BROADCAST_DESTROY_AFTER_TIMEOUT); - int broadcastId = 243; byte[] code = {0x00, 0x01, 0x00, 0x02}; synchronized (mService.mBroadcastCallbacks) { @@ -477,59 +451,77 @@ public class LeAudioBroadcastServiceTest { BluetoothLeBroadcastSettings settings = buildBroadcastSettingsFromMetadata(meta, code, 1); mService.createBroadcast(settings); - // Test data with only one subgroup - int[] expectedQualityArray = {settings.getSubgroupSettings().get(0).getPreferredQuality()}; - byte[][] expectedDataArray = { - settings.getSubgroupSettings().get(0).getContentMetadata().getRawMetadata() - }; - - verify(mLeAudioBroadcasterNativeInterface) - .createBroadcast( - eq(true), - eq(TEST_BROADCAST_NAME), - eq(code), - eq(settings.getPublicBroadcastMetadata().getRawMetadata()), - eq(expectedQualityArray), - eq(expectedDataArray)); - - // Check if broadcast is started automatically when created - LeAudioStackEvent create_event = - new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED); - create_event.valueInt1 = broadcastId; - create_event.valueBool1 = true; - mService.messageFromNative(create_event); - - // Verify if broadcast is auto-started on start - verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); - TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); - - Assert.assertTrue(mOnBroadcastStartedCalled); - - // Notify initial paused state - LeAudioStackEvent state_event = - new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE); - state_event.valueInt1 = broadcastId; - state_event.valueInt2 = LeAudioStackEvent.BROADCAST_STATE_PAUSED; - mService.messageFromNative(state_event); + if (Flags.leaudioBigDependsOnAudioState()) { + try { + verify(mCallbacks, timeout(CREATE_BROADCAST_TIMEOUT_MS).times(1)) + .onBroadcastStartFailed(eq(BluetoothStatusCodes.ERROR_TIMEOUT)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + int broadcastId = 243; + // Test data with only one subgroup + int[] expectedQualityArray = { + settings.getSubgroupSettings().get(0).getPreferredQuality() + }; + byte[][] expectedDataArray = { + settings.getSubgroupSettings().get(0).getContentMetadata().getRawMetadata() + }; - // Check if broadcast is destroyed after timeout - verify(mLeAudioBroadcasterNativeInterface, timeout(CREATE_BROADCAST_TIMEOUT_MS)) - .destroyBroadcast(eq(broadcastId)); + verify(mLeAudioBroadcasterNativeInterface) + .createBroadcast( + eq(true), + eq(TEST_BROADCAST_NAME), + eq(code), + eq(settings.getPublicBroadcastMetadata().getRawMetadata()), + eq(expectedQualityArray), + eq(expectedDataArray)); + + // Check if broadcast is started automatically when created + LeAudioStackEvent create_event = + new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED); + create_event.valueInt1 = broadcastId; + create_event.valueBool1 = true; + mService.messageFromNative(create_event); + + // Verify if broadcast is auto-started on start + verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); + TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); - state_event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_DESTROYED); - state_event.valueInt1 = broadcastId; - mService.messageFromNative(state_event); + try { + verify(mCallbacks, times(1)) + .onBroadcastStarted( + eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST), anyInt()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } - // Verify broadcast audio session is logged when session failed to stream - verify(mMetricsLogger) - .logLeAudioBroadcastAudioSession( - eq(broadcastId), - eq(new int[] {0x2}), // STATS_SESSION_AUDIO_QUALITY_HIGH - eq(0), - anyLong(), - anyLong(), - eq(0L), - eq(0x5)); // STATS_SESSION_SETUP_STATUS_STREAMING_FAILED + // Notify initial paused state + LeAudioStackEvent state_event = + new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE); + state_event.valueInt1 = broadcastId; + state_event.valueInt2 = LeAudioStackEvent.BROADCAST_STATE_PAUSED; + mService.messageFromNative(state_event); + + // Check if broadcast is destroyed after timeout + verify(mLeAudioBroadcasterNativeInterface, timeout(CREATE_BROADCAST_TIMEOUT_MS)) + .destroyBroadcast(eq(broadcastId)); + + state_event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_DESTROYED); + state_event.valueInt1 = broadcastId; + mService.messageFromNative(state_event); + + // Verify broadcast audio session is logged when session failed to stream + verify(mMetricsLogger) + .logLeAudioBroadcastAudioSession( + eq(broadcastId), + eq(new int[] {0x2}), // STATS_SESSION_AUDIO_QUALITY_HIGH + eq(0), + anyLong(), + anyLong(), + eq(0L), + eq(0x5)); // STATS_SESSION_SETUP_STATUS_STREAMING_FAILED + } } @Test @@ -649,8 +641,14 @@ public class LeAudioBroadcastServiceTest { TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); - Assert.assertFalse(mOnBroadcastStoppedCalled); - Assert.assertTrue(mOnBroadcastStopFailedCalled); + try { + verify(mCallbacks, times(0)).onBroadcastStopped(anyInt(), anyInt()); + verify(mCallbacks, times(1)) + .onBroadcastStopFailed( + eq(BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } // Update metadata for non-existing broadcast BluetoothLeAudioContentMetadata.Builder meta_builder = @@ -662,8 +660,12 @@ public class LeAudioBroadcastServiceTest { TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); - Assert.assertFalse(mOnBroadcastUpdatedCalled); - Assert.assertTrue(mOnBroadcastUpdateFailedCalled); + try { + verify(mCallbacks, times(0)).onBroadcastUpdated(anyInt(), anyInt()); + verify(mCallbacks, times(1)).onBroadcastUpdateFailed(anyInt(), anyInt()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } private BluetoothLeBroadcastSubgroup createBroadcastSubgroup() { @@ -977,19 +979,21 @@ public class LeAudioBroadcastServiceTest { TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); verifyBroadcastStarted(broadcastId, settings); - mOnBroadcastStartedCalled = false; - mOnBroadcastStartFailedCalled = false; + Mockito.clearInvocations(mCallbacks); // verify creating another broadcast will fail mService.createBroadcast(settings); TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper()); - Assert.assertFalse(mOnBroadcastStartedCalled); - Assert.assertTrue(mOnBroadcastStartFailedCalled); - Assert.assertEquals( - BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES, - mOnBroadcastStartFailedReason); + try { + verify(mCallbacks, times(0)).onBroadcastStarted(anyInt(), anyInt()); + verify(mCallbacks, times(1)) + .onBroadcastStartFailed( + eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } private void prepareHandoverStreamingBroadcast(int groupId, int broadcastId, byte[] code) { @@ -1083,9 +1087,6 @@ public class LeAudioBroadcastServiceTest { create_event.valueBool1 = true; mService.messageFromNative(create_event); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); - /* Switch to active streaming */ create_event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE); create_event.device = mBroadcastDevice; @@ -1108,6 +1109,8 @@ public class LeAudioBroadcastServiceTest { /* Imitate setting device in call */ mService.setInCall(true); + Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + /* Check if broadcast is paused by InCall handling */ verify(mLeAudioBroadcasterNativeInterface).pauseBroadcast(eq(broadcastId)); @@ -1155,8 +1158,8 @@ public class LeAudioBroadcastServiceTest { .handleBluetoothActiveDeviceChanged( eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class)); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + /* Verify if broadcast triggers transition */ + Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); } @Test @@ -1172,6 +1175,8 @@ public class LeAudioBroadcastServiceTest { /* Imitate setting device in call */ mService.handleAudioModeChange(AudioManager.MODE_IN_CALL); + Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + /* Check if broadcast is paused by AudioMode handling */ verify(mLeAudioBroadcasterNativeInterface).pauseBroadcast(eq(broadcastId)); @@ -1227,8 +1232,13 @@ public class LeAudioBroadcastServiceTest { .handleBluetoothActiveDeviceChanged( eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class)); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + if (Flags.leaudioBigDependsOnAudioState()) { + /* Verify if broadcast triggers transition */ + Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + } else { + /* Verify if broadcast is auto-started on start */ + verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + } } @Test @@ -1239,8 +1249,10 @@ public class LeAudioBroadcastServiceTest { prepareHandoverStreamingBroadcast(groupId, broadcastId, code); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); + if (!Flags.leaudioBigDependsOnAudioState()) { + /* Verify if broadcast is auto-started on start */ + verify(mLeAudioBroadcasterNativeInterface).startBroadcast(eq(broadcastId)); + } /* Imitate group change request by Bluetooth Sink HAL resume request */ LeAudioStackEvent create_event = @@ -1249,6 +1261,8 @@ public class LeAudioBroadcastServiceTest { create_event.valueInt2 = LeAudioStackEvent.STATUS_LOCAL_STREAM_REQUESTED; mService.messageFromNative(create_event); + Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + /* Check if broadcast is paused triggered by group change request */ verify(mLeAudioBroadcasterNativeInterface).pauseBroadcast(eq(broadcastId)); @@ -1297,8 +1311,13 @@ public class LeAudioBroadcastServiceTest { .handleBluetoothActiveDeviceChanged( eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class)); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + if (Flags.leaudioBigDependsOnAudioState()) { + /* Verify if broadcast triggers transition */ + Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + } else { + /* Verify if broadcast is auto-started on start */ + verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + } } @Test @@ -1321,6 +1340,8 @@ public class LeAudioBroadcastServiceTest { /* Imitate setting device in call */ mService.setInCall(true); + Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + /* Broadcast already paused, not call pause again by InCall handling */ verify(mLeAudioBroadcasterNativeInterface, never()).pauseBroadcast(eq(broadcastId)); @@ -1362,8 +1383,8 @@ public class LeAudioBroadcastServiceTest { .handleBluetoothActiveDeviceChanged( eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class)); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + /* Verify if broadcast triggers transition */ + Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); } @Test @@ -1386,6 +1407,8 @@ public class LeAudioBroadcastServiceTest { /* Imitate setting device in call */ mService.handleAudioModeChange(AudioManager.MODE_IN_CALL); + Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + /* Broadcast already paused, not call pause again by AudioMode handling */ verify(mLeAudioBroadcasterNativeInterface, never()).pauseBroadcast(eq(broadcastId)); @@ -1435,8 +1458,8 @@ public class LeAudioBroadcastServiceTest { .handleBluetoothActiveDeviceChanged( eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class)); - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + /* Verify if broadcast triggers transition */ + Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); } @Test @@ -1462,6 +1485,8 @@ public class LeAudioBroadcastServiceTest { create_event.valueInt2 = LeAudioStackEvent.STATUS_LOCAL_STREAM_REQUESTED; mService.messageFromNative(create_event); + Assert.assertTrue(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); + /* Broadcast already paused, not call pause again by group change request */ verify(mLeAudioBroadcasterNativeInterface, never()).pauseBroadcast(eq(broadcastId)); @@ -1503,9 +1528,8 @@ public class LeAudioBroadcastServiceTest { verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class)); - - /* Verify if broadcast is auto-started on start */ - verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId)); + /* Verify if broadcast triggers transition */ + Assert.assertFalse(mService.mBroadcastIdDeactivatedForUnicastTransition.isPresent()); } @Test 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 f49529c65e..3176c78f6a 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 @@ -291,7 +291,6 @@ public class TransitionalScanHelperTest { @Test public void onScanResult_remoteException_clientDied() throws Exception { - mSetFlagsRule.enableFlags(Flags.FLAG_LE_SCAN_FIX_REMOTE_EXCEPTION); int scannerId = 1; int eventType = 0; 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 e8f65e3966..042666d321 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 @@ -2156,9 +2156,7 @@ public class BluetoothMapContentObserverTest { // This mock sets type to MMS doReturn(4) .when(mIntent) - .getIntExtra( - BluetoothMapContentObserver.EXTRA_MESSAGE_SENT_MSG_TYPE, - TYPE.NONE.ordinal()); + .getIntExtra(eq(BluetoothMapContentObserver.EXTRA_MESSAGE_SENT_MSG_TYPE), anyInt()); mObserver.actionMessageSentDisconnected(mContext, mIntent, 1); @@ -2177,9 +2175,7 @@ public class BluetoothMapContentObserverTest { // This mock sets type to Email doReturn(1) .when(mIntent) - .getIntExtra( - BluetoothMapContentObserver.EXTRA_MESSAGE_SENT_MSG_TYPE, - TYPE.NONE.ordinal()); + .getIntExtra(eq(BluetoothMapContentObserver.EXTRA_MESSAGE_SENT_MSG_TYPE), anyInt()); clearInvocations(mContext); mObserver.actionMessageSentDisconnected(mContext, mIntent, Activity.RESULT_FIRST_USER); diff --git a/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapbMessageSmsTest.java b/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapbMessageSmsTest.java index e55117a037..a43c63d033 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapbMessageSmsTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapbMessageSmsTest.java @@ -16,9 +16,12 @@ package com.android.bluetooth.map; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY_MESSAGING; + import static com.google.common.truth.Truth.assertThat; import android.content.Context; +import android.content.pm.PackageManager; import android.telephony.SmsManager; import androidx.test.InstrumentationRegistry; @@ -50,7 +53,11 @@ public class BluetoothMapbMessageSmsTest { @Before public void setUp() throws Exception { // Do not run test if sms is not supported + PackageManager packageManager = + InstrumentationRegistry.getTargetContext().getPackageManager(); + Assume.assumeTrue(packageManager.isPackageAvailable(FEATURE_TELEPHONY_MESSAGING)); Assume.assumeTrue(mSmsManager.isImsSmsSupported()); + mTargetContext = InstrumentationRegistry.getTargetContext(); TEST_SMS_BODY_PDUS = BluetoothMapSmsPdu.getSubmitPdus(mTargetContext, TEST_MESSAGE, TEST_ADDRESS); diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceCleanupTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceCleanupTest.java index d2db49fbc5..2183c19347 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceCleanupTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppServiceCleanupTest.java @@ -46,7 +46,7 @@ public class BluetoothOppServiceCleanupTest { @Test @UiThreadTest - public void testStopAndCleanup() { + public void testStopAndCleanup() throws Exception { AdapterService adapterService = new AdapterService(mTargetContext); // Don't need to disable again since it will be handled in OppService.stop @@ -58,8 +58,9 @@ public class BluetoothOppServiceCleanupTest { mTargetContext.getContentResolver().insert(BluetoothShare.CONTENT_URI, values); } + BluetoothOppService service = null; try { - BluetoothOppService service = new BluetoothOppService(adapterService); + service = new BluetoothOppService(adapterService); service.start(); service.setAvailable(true); @@ -67,6 +68,12 @@ public class BluetoothOppServiceCleanupTest { service.stop(); service.cleanup(); } finally { + if (service != null) { + Thread updateNotificationThread = service.mNotifier.mUpdateNotificationThread; + if (updateNotificationThread != null) { + updateNotificationThread.join(); + } + } mTargetContext.getContentResolver().delete(BluetoothShare.CONTENT_URI, null, null); } } 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 22affe39cf..4b5bd23465 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 @@ -107,6 +107,10 @@ public class BluetoothOppServiceTest { BluetoothOppService service = mService; if (service != null) { service.mUpdateThread = null; + Thread updateNotificationThread = service.mNotifier.mUpdateNotificationThread; + if (updateNotificationThread != null) { + updateNotificationThread.join(); + } } BluetoothMethodProxy.setInstanceForTesting(null); diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java index 2f734f585f..9b0aa48c62 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlNativeInterfaceTest.java @@ -21,6 +21,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothProfile; + import androidx.test.runner.AndroidJUnit4; import org.junit.After; @@ -55,7 +57,7 @@ public class VolumeControlNativeInterfaceTest { @Test public void onConnectionStateChanged() { - int state = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; + int state = BluetoothProfile.STATE_CONNECTED; byte[] address = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; mNativeInterface.onConnectionStateChanged(state, address); 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 22ec653e36..c753899100 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 @@ -17,9 +17,32 @@ package com.android.bluetooth.vc; +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.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.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID; -import static org.mockito.Mockito.*; +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.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -28,20 +51,16 @@ import android.bluetooth.BluetoothUuid; import android.bluetooth.BluetoothVolumeControl; import android.bluetooth.IBluetoothVolumeControlCallback; import android.content.AttributionSource; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.media.AudioManager; import android.os.Binder; -import android.os.Looper; import android.os.ParcelUuid; +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.platform.app.InstrumentationRegistry; -import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.TestUtils; @@ -53,46 +72,31 @@ import com.android.bluetooth.csip.CsipSetCoordinatorService; import com.android.bluetooth.flags.Flags; 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.Mockito; +import org.mockito.hamcrest.MockitoHamcrest; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; import java.util.stream.IntStream; @MediumTest @RunWith(AndroidJUnit4.class) public class VolumeControlServiceTest { - private BluetoothAdapter mAdapter; - private AttributionSource mAttributionSource; - private Context mTargetContext; - private VolumeControlService mService; - private VolumeControlService.BluetoothVolumeControlBinder mServiceBinder; - private BluetoothDevice mDevice; - private BluetoothDevice mDeviceTwo; - private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mDeviceQueueMap; - private static final int TIMEOUT_MS = 1000; - private static final int BT_LE_AUDIO_MAX_VOL = 255; - private static final int MEDIA_MIN_VOL = 0; - private static final int MEDIA_MAX_VOL = 25; - private static final int CALL_MIN_VOL = 1; - private static final int CALL_MAX_VOL = 8; - private static final int TEST_GROUP_ID = 1; - - private BroadcastReceiver mVolumeControlIntentReceiver; - @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Mock private AdapterService mAdapterService; @Mock private BassClientService mBassClientService; @@ -103,22 +107,41 @@ public class VolumeControlServiceTest { @Mock private ServiceFactory mServiceFactory; @Mock private CsipSetCoordinatorService mCsipService; - @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule(); - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private static final int BT_LE_AUDIO_MAX_VOL = 255; + private static final int MEDIA_MIN_VOL = 0; + private static final int MEDIA_MAX_VOL = 25; + private static final int CALL_MIN_VOL = 1; + private static final int CALL_MAX_VOL = 8; + private static final int TEST_GROUP_ID = 1; + + private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); + private final BluetoothDevice mDevice = TestUtils.getTestDevice(mAdapter, 134); + private final BluetoothDevice mDeviceTwo = TestUtils.getTestDevice(mAdapter, 231); + + private AttributionSource mAttributionSource; + private VolumeControlService mService; + private VolumeControlService.BluetoothVolumeControlBinder mBinder; + private InOrder mInOrder; + private TestLooper mLooper; @Before - public void setUp() throws Exception { - mTargetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + public void setUp() { + doReturn(true).when(mNativeInterface).connectVolumeControl(any()); + doReturn(true).when(mNativeInterface).disconnectVolumeControl(any()); - if (Looper.myLooper() == null) { - Looper.prepare(); - } + doReturn(CONNECTION_POLICY_ALLOWED) + .when(mDatabaseManager) + .getProfileConnectionPolicy(any(), anyInt()); - TestUtils.setAdapterService(mAdapterService); doReturn(mDatabaseManager).when(mAdapterService).getDatabase(); + doReturn(BOND_BONDED).when(mAdapterService).getBondState(any()); + doReturn(new ParcelUuid[] {BluetoothUuid.VOLUME_CONTROL}) + .when(mAdapterService) + .getRemoteUuids(any(BluetoothDevice.class)); - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mAttributionSource = mAdapter.getAttributionSource(); + doReturn(mCsipService).when(mServiceFactory).getCsipSetCoordinatorService(); + doReturn(mLeAudioService).when(mServiceFactory).getLeAudioService(); + doReturn(mBassClientService).when(mServiceFactory).getBassClientService(); doReturn(MEDIA_MIN_VOL) .when(mAudioManager) @@ -132,432 +155,243 @@ public class VolumeControlServiceTest { doReturn(CALL_MAX_VOL) .when(mAudioManager) .getStreamMaxVolume(eq(AudioManager.STREAM_VOICE_CALL)); + TestUtils.mockGetSystemService( + mAdapterService, Context.AUDIO_SERVICE, AudioManager.class, mAudioManager); + + mInOrder = inOrder(mAdapterService); + mLooper = new TestLooper(); - VolumeControlNativeInterface.setInstance(mNativeInterface); - mService = new VolumeControlService(mTargetContext); - mService.start(); + mAttributionSource = mAdapter.getAttributionSource(); + mService = new VolumeControlService(mAdapterService, mLooper.getLooper(), mNativeInterface); mService.setAvailable(true); - mService.mAudioManager = mAudioManager; mService.mFactory = mServiceFactory; - mServiceBinder = (VolumeControlService.BluetoothVolumeControlBinder) mService.initBinder(); - - doReturn(mCsipService).when(mServiceFactory).getCsipSetCoordinatorService(); - doReturn(mLeAudioService).when(mServiceFactory).getLeAudioService(); - doReturn(mBassClientService).when(mServiceFactory).getBassClientService(); - - // Override the timeout value to speed up the test - VolumeControlStateMachine.sConnectTimeoutMs = TIMEOUT_MS; // 1s - - // Set up the Connection State Changed receiver - IntentFilter filter = new IntentFilter(); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - filter.addAction(BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED); - - mVolumeControlIntentReceiver = new VolumeControlIntentReceiver(); - mTargetContext.registerReceiver(mVolumeControlIntentReceiver, filter); - - // Get a device for testing - mDevice = TestUtils.getTestDevice(mAdapter, 0); - mDeviceTwo = TestUtils.getTestDevice(mAdapter, 1); - mDeviceQueueMap = new HashMap<>(); - mDeviceQueueMap.put(mDevice, new LinkedBlockingQueue<>()); - mDeviceQueueMap.put(mDeviceTwo, new LinkedBlockingQueue<>()); - doReturn(BluetoothDevice.BOND_BONDED) - .when(mAdapterService) - .getBondState(any(BluetoothDevice.class)); - doReturn(new ParcelUuid[] {BluetoothUuid.VOLUME_CONTROL}) - .when(mAdapterService) - .getRemoteUuids(any(BluetoothDevice.class)); + mBinder = (VolumeControlService.BluetoothVolumeControlBinder) mService.initBinder(); } @After - public void tearDown() throws Exception { - if (mService == null) { - return; - } - + public void tearDown() { + assertThat(mLooper.nextMessage()).isNull(); mService.stop(); - VolumeControlNativeInterface.setInstance(null); - mTargetContext.unregisterReceiver(mVolumeControlIntentReceiver); - mDeviceQueueMap.clear(); - TestUtils.clearAdapterService(mAdapterService); - reset(mAudioManager); - } - - private class VolumeControlIntentReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - try { - BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - Assert.assertNotNull(device); - LinkedBlockingQueue<Intent> queue = mDeviceQueueMap.get(device); - Assert.assertNotNull(queue); - queue.put(intent); - } catch (InterruptedException e) { - Assert.fail("Cannot add Intent to the Connection State queue: " + e.getMessage()); - } - } - } - - private void verifyConnectionStateIntent( - int timeoutMs, BluetoothDevice device, int newState, int prevState) { - Intent intent = TestUtils.waitForIntent(timeoutMs, mDeviceQueueMap.get(device)); - Assert.assertNotNull(intent); - Assert.assertEquals( - BluetoothVolumeControl.ACTION_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)); - } - - private void verifyNoConnectionStateIntent(int timeoutMs, BluetoothDevice device) { - Intent intent = TestUtils.waitForNoIntent(timeoutMs, mDeviceQueueMap.get(device)); - Assert.assertNull(intent); + mLooper.dispatchAll(); + assertThat(VolumeControlService.getVolumeControlService()).isNull(); } - /** Test getting VolumeControl Service: getVolumeControlService() */ @Test - public void testGetVolumeControlService() { - Assert.assertEquals(mService, VolumeControlService.getVolumeControlService()); + public void getVolumeControlService() { + assertThat(VolumeControlService.getVolumeControlService()).isEqualTo(mService); } - /** Test stop VolumeControl Service */ @Test - public void testStopVolumeControlService() throws Exception { - // Prepare: connect - connectDevice(mDevice); - // VolumeControl Service is already running: test stop(). - // Note: must be done on the main thread - InstrumentationRegistry.getInstrumentation().runOnMainSync(mService::stop); - // Try to restart the service. Note: must be done on the main thread - InstrumentationRegistry.getInstrumentation().runOnMainSync(mService::start); - } - - /** Test get/set policy for BluetoothDevice */ - @Test - public void testGetSetPolicy() { - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); - Assert.assertEquals( - "Initial device policy", - BluetoothProfile.CONNECTION_POLICY_UNKNOWN, - mService.getConnectionPolicy(mDevice)); - - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); - Assert.assertEquals( - "Setting device policy to POLICY_FORBIDDEN", - BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, - mService.getConnectionPolicy(mDevice)); - - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - Assert.assertEquals( - "Setting device policy to POLICY_ALLOWED", - BluetoothProfile.CONNECTION_POLICY_ALLOWED, - mService.getConnectionPolicy(mDevice)); + 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() throws Exception { - mService.stop(); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); - int policy = mServiceBinder.getConnectionPolicy(mDevice, mAttributionSource); - Assert.assertEquals( - "Initial device policy", BluetoothProfile.CONNECTION_POLICY_UNKNOWN, policy); + 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( - mDevice, - BluetoothDevice.BOND_NONE, - BluetoothProfile.CONNECTION_POLICY_UNKNOWN, - false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_NONE, - BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, - false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_NONE, - BluetoothProfile.CONNECTION_POLICY_ALLOWED, - false); - testOkToConnectCase(mDevice, BluetoothDevice.BOND_NONE, badPolicyValue, false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_BONDING, - BluetoothProfile.CONNECTION_POLICY_UNKNOWN, - false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_BONDING, - BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, - false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_BONDING, - BluetoothProfile.CONNECTION_POLICY_ALLOWED, - false); - testOkToConnectCase(mDevice, BluetoothDevice.BOND_BONDING, badPolicyValue, false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_BONDED, - BluetoothProfile.CONNECTION_POLICY_UNKNOWN, - true); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_BONDED, - BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, - false); - testOkToConnectCase( - mDevice, - BluetoothDevice.BOND_BONDED, - BluetoothProfile.CONNECTION_POLICY_ALLOWED, - true); - testOkToConnectCase(mDevice, BluetoothDevice.BOND_BONDED, badPolicyValue, false); - testOkToConnectCase( - mDevice, badBondState, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false); - testOkToConnectCase( - mDevice, badBondState, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false); - testOkToConnectCase( - mDevice, badBondState, BluetoothProfile.CONNECTION_POLICY_ALLOWED, false); - testOkToConnectCase(mDevice, 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 an outgoing connection to device that does not have Volume Control UUID is rejected - */ @Test - public void testOutgoingConnectMissingVolumeControlUuid() { - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - + public void connectToDevice_whenUuidIsMissing_returnFalse() { // Return No UUID doReturn(new ParcelUuid[] {}) .when(mAdapterService) .getRemoteUuids(any(BluetoothDevice.class)); - // Send a connect request - Assert.assertFalse("Connect expected to fail", mService.connect(mDevice)); + assertThat(mService.connect(mDevice)).isFalse(); + } + + @Test + public void disconnect_whenConnecting_isDisconnectedWithBroadcast() { + assertThat(mService.connect(mDevice)).isTrue(); + mLooper.dispatchAll(); + verifyConnectionStateIntent(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + + assertThat(mService.disconnect(mDevice)).isTrue(); + mLooper.dispatchAll(); + verifyConnectionStateIntent(mDevice, STATE_DISCONNECTED, STATE_CONNECTING); } - /** Test that an outgoing connection to device that have Volume Control UUID is successful */ @Test - public void testOutgoingConnectDisconnectExistingVolumeControlUuid() throws Exception { - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); + public void connectToDevice_whenPolicyForbid_returnFalse() { when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + .thenReturn(CONNECTION_POLICY_FORBIDDEN); - // Return Volume Control UUID - doReturn(new ParcelUuid[] {BluetoothUuid.VOLUME_CONTROL}) - .when(mAdapterService) - .getRemoteUuids(any(BluetoothDevice.class)); + assertThat(mService.connect(mDevice)).isFalse(); + } - // Send a connect request - Assert.assertTrue("Connect expected to succeed", mService.connect(mDevice)); + @Test + public void outgoingConnect_whenTimeOut_isDisconnected() { + assertThat(mService.connect(mDevice)).isTrue(); + mLooper.dispatchAll(); - // Verify the connection state broadcast, and that we are in Connecting state - verifyConnectionStateIntent( - TIMEOUT_MS, - mDevice, - BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTED); + verifyConnectionStateIntent(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); - // Send a disconnect request - Assert.assertTrue("Disconnect expected to succeed", mService.disconnect(mDevice)); + mLooper.moveTimeForward(VolumeControlStateMachine.CONNECT_TIMEOUT.toMillis()); + mLooper.dispatchAll(); - // Verify the connection state broadcast, and that we are in Connecting state - verifyConnectionStateIntent( - TIMEOUT_MS, - mDevice, - BluetoothProfile.STATE_DISCONNECTED, - BluetoothProfile.STATE_CONNECTING); + verifyConnectionStateIntent(mDevice, STATE_DISCONNECTED, STATE_CONNECTING); } - /** Test that an outgoing connection to device with POLICY_FORBIDDEN is rejected */ @Test - public void testOutgoingConnectPolicyForbidden() { - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - - // Set the device policy to POLICY_FORBIDDEN so connect() should fail - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); - - // Send a connect request - Assert.assertFalse("Connect expected to fail", mService.connect(mDevice)); + public void incomingConnecting_whenNoDevice_createStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + assertThat(mService.getDevices()).contains(mDevice); } - /** Test that an outgoing connection times out */ @Test - public void testOutgoingConnectTimeout() throws Exception { - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + public void incomingDisconnect_whenConnectingDevice_keepStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); - // Send a connect request - Assert.assertTrue("Connect failed", mService.connect(mDevice)); - - // Verify the connection state broadcast, and that we are in Connecting state - verifyConnectionStateIntent( - TIMEOUT_MS, - mDevice, - BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mDevice)); - - // Verify the connection state broadcast, and that we are in Disconnected state - verifyConnectionStateIntent( - VolumeControlStateMachine.sConnectTimeoutMs * 2, - mDevice, - BluetoothProfile.STATE_DISCONNECTED, - BluetoothProfile.STATE_CONNECTING); - - int state = mServiceBinder.getConnectionState(mDevice, mAttributionSource); - Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, state); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTED, STATE_CONNECTING); + assertThat(mService.getDevices()).contains(mDevice); } - /** - * Test that only CONNECTION_STATE_CONNECTED or CONNECTION_STATE_CONNECTING Volume Control stack - * events will create a state machine. - */ @Test - public void testCreateStateMachineStackEvents() { - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + public void incomingConnect_whenNoDevice_createStateMachine() { + // Theoretically impossible case + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); + } - // stack event: CONNECTION_STATE_CONNECTING - state machine should be created - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + @Test + public void incomingDisconnect_whenConnectedDevice_keepStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); - // stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); - mService.bondStateChanged(mDevice, BluetoothDevice.BOND_NONE); - Assert.assertFalse(mService.getDevices().contains(mDevice)); - - // stack event: CONNECTION_STATE_CONNECTED - state machine should be created - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTED, STATE_CONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTED); + assertThat(mService.getDevices()).contains(mDevice); + } - // stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); - mService.bondStateChanged(mDevice, BluetoothDevice.BOND_NONE); - Assert.assertFalse(mService.getDevices().contains(mDevice)); - - // stack event: CONNECTION_STATE_DISCONNECTING - state machine should not be created - generateUnexpectedConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_DISCONNECTING); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mDevice)); - Assert.assertFalse(mService.getDevices().contains(mDevice)); - - // stack event: CONNECTION_STATE_DISCONNECTED - state machine should not be created - generateUnexpectedConnectionMessageFromNative(mDevice, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mDevice)); - Assert.assertFalse(mService.getDevices().contains(mDevice)); + @Test + public void incomingDisconnecting_whenNoDevice_noStateMachine() { + generateUnexpectedConnectionMessageFromNative(mDevice, STATE_DISCONNECTING); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTED); + assertThat(mService.getDevices()).doesNotContain(mDevice); } - /** - * Test that a CONNECTION_STATE_DISCONNECTED Volume Control stack event will remove the state - * machine only if the device is unbond. - */ @Test - public void testDeleteStateMachineDisconnectEvents() { - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(mDevice, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); + public void incomingDisconnect_whenNoDevice_noStateMachine() { + generateUnexpectedConnectionMessageFromNative(mDevice, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTED); + assertThat(mService.getDevices()).doesNotContain(mDevice); + } - // stack event: CONNECTION_STATE_CONNECTING - state machine should be created - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + @Test + public void unBondDevice_whenConnecting_keepStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTING); + assertThat(mService.getDevices()).contains(mDevice); + + mService.bondStateChanged(mDevice, BOND_NONE); + assertThat(mService.getDevices()).contains(mDevice); + assertThat(mLooper.nextMessage().what) + .isEqualTo(VolumeControlStateMachine.MESSAGE_DISCONNECT); + } - // stack event: CONNECTION_STATE_DISCONNECTED - state machine is not removed - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + @Test + public void unBondDevice_whenConnected_keepStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_CONNECTING); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); + + mService.bondStateChanged(mDevice, BOND_NONE); + assertThat(mService.getDevices()).contains(mDevice); + assertThat(mLooper.nextMessage().what) + .isEqualTo(VolumeControlStateMachine.MESSAGE_DISCONNECT); + } - // stack event: CONNECTION_STATE_CONNECTING - state machine remains - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + @Test + public void unBondDevice_whenDisconnecting_keepStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_CONNECTING); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTING, STATE_CONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTING); + assertThat(mService.getDevices()).contains(mDevice); + + mService.bondStateChanged(mDevice, BOND_NONE); + assertThat(mService.getDevices()).contains(mDevice); + assertThat(mLooper.nextMessage().what) + .isEqualTo(VolumeControlStateMachine.MESSAGE_DISCONNECT); + } - // device bond state marked as unbond - state machine is not removed - doReturn(BluetoothDevice.BOND_NONE) - .when(mAdapterService) - .getBondState(any(BluetoothDevice.class)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + @Test + public void unBondDevice_whenDisconnected_removeStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_CONNECTING); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTING, STATE_CONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTED, STATE_DISCONNECTING); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTED); + assertThat(mService.getDevices()).contains(mDevice); + + mService.bondStateChanged(mDevice, BOND_NONE); + mLooper.dispatchAll(); + assertThat(mService.getDevices()).doesNotContain(mDevice); + } - // stack event: CONNECTION_STATE_DISCONNECTED - state machine is removed - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mDevice)); - Assert.assertFalse(mService.getDevices().contains(mDevice)); + @Test + public void disconnect_whenBonded_keepStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_CONNECTING); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTING, STATE_CONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTED, STATE_DISCONNECTING); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTED); + assertThat(mService.getDevices()).contains(mDevice); } - /** Test that various Volume Control stack events will broadcast related states. */ @Test - public void testVolumeControlStackEvents() { - int group_id = -1; - int volume = 6; - int flags = 0; - boolean mute = false; - boolean isAutonomous = false; + public void disconnect_whenUnBonded_removeStateMachine() { + generateConnectionMessageFromNative(mDevice, STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_CONNECTING); + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTING, STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); - // Send a message to trigger volume state changed broadcast - generateVolumeStateChanged(mDevice, group_id, volume, flags, mute, isAutonomous); + doReturn(BOND_NONE).when(mAdapterService).getBondState(any()); + mService.bondStateChanged(mDevice, BOND_NONE); + assertThat(mService.getDevices()).contains(mDevice); + + generateConnectionMessageFromNative(mDevice, STATE_DISCONNECTED, STATE_DISCONNECTING); + + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_DISCONNECTED); + assertThat(mService.getDevices()).doesNotContain(mDevice); } int getLeAudioVolume(int index, int minIndex, int maxIndex, int streamType) { @@ -591,7 +425,7 @@ public class VolumeControlServiceTest { } @Test - public void testAutonomousVolumeStateChange() { + public void incomingAutonomousVolumeStateChange_isApplied() { // Make device Active now. This will trigger setting volume to AF when(mLeAudioService.getActiveGroupId()).thenReturn(TEST_GROUP_ID); @@ -602,9 +436,8 @@ public class VolumeControlServiceTest { testVolumeCalculations(AudioManager.STREAM_MUSIC, MEDIA_MIN_VOL, MEDIA_MAX_VOL); } - /** Test if autonomous Mute/Unmute propagates the event to audio manager. */ @Test - public void testAutonomousMuteUnmute() { + public void incomingAutonomousMuteUnmute_isApplied() { int streamType = AudioManager.STREAM_MUSIC; int streamVol = getLeAudioVolume(19, MEDIA_MIN_VOL, MEDIA_MAX_VOL, streamType); @@ -626,43 +459,41 @@ public class VolumeControlServiceTest { .adjustStreamVolume(eq(streamType), eq(AudioManager.ADJUST_UNMUTE), anyInt()); } - /** Test Volume Control cache. */ @Test - public void testVolumeCache() throws Exception { + public void volumeCache() { int groupId = 1; int volume = 6; - Assert.assertEquals(-1, mService.getGroupVolume(groupId)); - mServiceBinder.setGroupVolume(groupId, volume, mAttributionSource); + assertThat(mService.getGroupVolume(groupId)).isEqualTo(-1); + mBinder.setGroupVolume(groupId, volume, mAttributionSource); - int groupVolume = mServiceBinder.getGroupVolume(groupId, mAttributionSource); - Assert.assertEquals(volume, groupVolume); + int groupVolume = mBinder.getGroupVolume(groupId, mAttributionSource); + assertThat(groupVolume).isEqualTo(volume); volume = 10; // Send autonomous volume change. generateVolumeStateChanged(null, groupId, volume, 0, false, true); - Assert.assertEquals(volume, mService.getGroupVolume(groupId)); + assertThat(mService.getGroupVolume(groupId)).isEqualTo(volume); } - /** Test Active Group change */ @Test - public void testActiveGroupChange() throws Exception { + public void activeGroupChange() { int groupId_1 = 1; int volume_groupId_1 = 6; int groupId_2 = 2; int volume_groupId_2 = 20; - Assert.assertEquals(-1, mService.getGroupVolume(groupId_1)); - Assert.assertEquals(-1, mService.getGroupVolume(groupId_2)); - mServiceBinder.setGroupVolume(groupId_1, volume_groupId_1, mAttributionSource); + assertThat(mService.getGroupVolume(groupId_1)).isEqualTo(-1); + assertThat(mService.getGroupVolume(groupId_2)).isEqualTo(-1); + mBinder.setGroupVolume(groupId_1, volume_groupId_1, mAttributionSource); - mServiceBinder.setGroupVolume(groupId_2, volume_groupId_2, mAttributionSource); + mBinder.setGroupVolume(groupId_2, volume_groupId_2, mAttributionSource); // Make device Active now. This will trigger setting volume to AF when(mLeAudioService.getActiveGroupId()).thenReturn(groupId_1); - mServiceBinder.setGroupActive(groupId_1, true, mAttributionSource); + mBinder.setGroupActive(groupId_1, true, mAttributionSource); // Expected index for STREAM_MUSIC int expectedVol = @@ -671,77 +502,76 @@ public class VolumeControlServiceTest { // Make device Active now. This will trigger setting volume to AF when(mLeAudioService.getActiveGroupId()).thenReturn(groupId_2); - mServiceBinder.setGroupActive(groupId_2, true, mAttributionSource); + mBinder.setGroupActive(groupId_2, true, mAttributionSource); expectedVol = (int) Math.round((double) (volume_groupId_2 * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL); verify(mAudioManager).setStreamVolume(anyInt(), eq(expectedVol), anyInt()); } - /** Test Volume Control Mute cache. */ @Test - public void testMuteCache() throws Exception { + public void muteCache() { int groupId = 1; int volume = 6; - Assert.assertEquals(false, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isFalse(); // Send autonomous volume change generateVolumeStateChanged(null, groupId, volume, 0, false, true); // Mute - mServiceBinder.muteGroup(groupId, mAttributionSource); - Assert.assertEquals(true, mService.getGroupMute(groupId)); + mBinder.muteGroup(groupId, mAttributionSource); + assertThat(mService.getGroupMute(groupId)).isTrue(); // Make sure the volume is kept even when muted - Assert.assertEquals(volume, mService.getGroupVolume(groupId)); + assertThat(mService.getGroupVolume(groupId)).isEqualTo(volume); // Send autonomous unmute generateVolumeStateChanged(null, groupId, volume, 0, false, true); - Assert.assertEquals(false, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isFalse(); } /** Test Volume Control with muted stream. */ @Test - public void testVolumeChangeWhileMuted() throws Exception { + public void volumeChangeWhileMuted() { int groupId = 1; int volume = 6; - Assert.assertEquals(false, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isFalse(); generateVolumeStateChanged(null, groupId, volume, 0, false, true); // Mute mService.muteGroup(groupId); - Assert.assertEquals(true, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isTrue(); verify(mNativeInterface).muteGroup(eq(groupId)); // Make sure the volume is kept even when muted doReturn(true).when(mAudioManager).isStreamMute(eq(AudioManager.STREAM_MUSIC)); - Assert.assertEquals(volume, mService.getGroupVolume(groupId)); + assertThat(mService.getGroupVolume(groupId)).isEqualTo(volume); // Lower the volume and keep it mute mService.setGroupVolume(groupId, --volume); - Assert.assertEquals(true, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isTrue(); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume)); - verify(mNativeInterface, times(0)).unmuteGroup(eq(groupId)); + verify(mNativeInterface, never()).unmuteGroup(eq(groupId)); // Don't unmute on consecutive calls either mService.setGroupVolume(groupId, --volume); - Assert.assertEquals(true, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isTrue(); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume)); - verify(mNativeInterface, times(0)).unmuteGroup(eq(groupId)); + verify(mNativeInterface, never()).unmuteGroup(eq(groupId)); // 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); - Assert.assertEquals(false, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isFalse(); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume)); // Verify the number of unmute calls after the second volume change mService.setGroupVolume(groupId, ++volume); - Assert.assertEquals(false, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isFalse(); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume)); // Make sure we unmuted only once verify(mNativeInterface).unmuteGroup(eq(groupId)); @@ -750,7 +580,7 @@ public class VolumeControlServiceTest { /** Test if phone will set volume which is read from the buds */ @Test @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_VOLUME_CONTROL_PRIMARY_GROUP_ONLY) - public void testConnectedDeviceWithUserPersistFlagSet() throws Exception { + public void connectedDeviceWithUserPersistFlagSet() { int groupId = 1; int volumeDevice = 56; int volumeDeviceTwo = 100; @@ -762,29 +592,20 @@ public class VolumeControlServiceTest { when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 1); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); 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, times(0)).setStreamVolume(anyInt(), anyInt(), anyInt()); + verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt()); // Make device Active now. This will trigger setting volume to AF when(mLeAudioService.getActiveGroupId()).thenReturn(groupId); - mServiceBinder.setGroupActive(groupId, true, mAttributionSource); + mBinder.setGroupActive(groupId, true, mAttributionSource); int expectedAfVol = (int) Math.round((double) (volumeDevice * MEDIA_MAX_VOL) / BT_LE_AUDIO_MAX_VOL); verify(mAudioManager).setStreamVolume(anyInt(), eq(expectedAfVol), anyInt()); @@ -792,11 +613,9 @@ public class VolumeControlServiceTest { // Connect second device and read different volume. Expect it will be set to AF and to // another set member generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + 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( @@ -828,19 +647,10 @@ public class VolumeControlServiceTest { when(mAudioManager.getStreamVolume(anyInt())).thenReturn(streamVolume); when(mAudioManager.getStreamMaxVolume(anyInt())).thenReturn(streamMaxVolume); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 1); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); int expectedAfVol = (int) Math.round((double) streamVolume * BT_LE_AUDIO_MAX_VOL / streamMaxVolume); @@ -853,11 +663,11 @@ public class VolumeControlServiceTest { resetFlag, initialMuteState, initialAutonomousFlag); - verify(mAudioManager, times(0)).setStreamVolume(anyInt(), anyInt(), anyInt()); + verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt()); // Make device Active now. This will trigger setting volume to AF when(mLeAudioService.getActiveGroupId()).thenReturn(groupId); - mServiceBinder.setGroupActive(groupId, true, mAttributionSource); + mBinder.setGroupActive(groupId, true, mAttributionSource); verify(mAudioManager).setStreamVolume(anyInt(), eq(streamVolume), anyInt()); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(expectedAfVol)); @@ -865,11 +675,9 @@ public class VolumeControlServiceTest { // Connect second device and read different volume. Expect it will be set to AF and to // another set member generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + 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( @@ -886,13 +694,13 @@ public class VolumeControlServiceTest { /** Test if phone will set volume which is read from the buds */ @Test - public void testConnectedDeviceWithResetFlagSetWithNonZeroVolume() throws Exception { + public void connectedDeviceWithResetFlagSetWithNonZeroVolume() { testConnectedDeviceWithResetFlag(56, 100); } /** Test if phone will set volume to buds which has no volume */ @Test - public void testConnectedDeviceWithResetFlagSetWithZeroVolume() throws Exception { + public void connectedDeviceWithResetFlagSetWithZeroVolume() { testConnectedDeviceWithResetFlag(0, 0); } @@ -901,7 +709,7 @@ public class VolumeControlServiceTest { * already changed and cached. */ @Test - public void testLateConnectingDevice() throws Exception { + public void lateConnectingDevice() { int groupId = 1; int groupVolume = 56; @@ -909,29 +717,18 @@ public class VolumeControlServiceTest { when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); mService.setGroupVolume(groupId, groupVolume); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume)); - verify(mNativeInterface, times(0)).setVolume(eq(mDeviceTwo), eq(groupVolume)); + verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(groupVolume)); // Verify that second device gets the proper group volume level when connected - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + 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)); } @@ -940,7 +737,7 @@ public class VolumeControlServiceTest { * group was already changed and cached. */ @Test - public void testLateDiscoveredGroupMember() throws Exception { + public void lateDiscoveredGroupMember() { int groupId = 1; int groupVolume = 56; @@ -948,29 +745,18 @@ public class VolumeControlServiceTest { when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(-1); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); // Set the group volume mService.setGroupVolume(groupId, groupVolume); // Verify that second device will not get the group volume level if it is not a group member - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); - verify(mNativeInterface, times(0)).setVolume(eq(mDeviceTwo), eq(groupVolume)); + 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)); // But gets the volume when it becomes the group member when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); @@ -984,7 +770,7 @@ public class VolumeControlServiceTest { * telephony, thus setting volume level to 0 is considered as muting. */ @Test - public void testMuteLateConnectingDevice() throws Exception { + public void muteLateConnectingDevice() { int groupId = 1; int volume = 100; @@ -992,36 +778,25 @@ public class VolumeControlServiceTest { when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); // Set the initial volume and mute conditions doReturn(true).when(mAudioManager).isStreamMute(anyInt()); mService.setGroupVolume(groupId, volume); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(volume)); - verify(mNativeInterface, times(0)).setVolume(eq(mDeviceTwo), eq(volume)); + verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(volume)); // Check if it was muted verify(mNativeInterface).muteGroup(eq(groupId)); - Assert.assertEquals(true, mService.getGroupMute(groupId)); + assertThat(mService.getGroupMute(groupId)).isTrue(); // Verify that second device gets the proper group volume level when connected - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + 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)); // Check if new device was muted verify(mNativeInterface).mute(eq(mDeviceTwo)); @@ -1033,7 +808,7 @@ public class VolumeControlServiceTest { * than telephony, thus setting volume level to 0 is considered as muting. */ @Test - public void testMuteLateDiscoveredGroupMember() throws Exception { + public void muteLateDiscoveredGroupMember() { int groupId = 1; int volume = 100; @@ -1041,32 +816,21 @@ public class VolumeControlServiceTest { when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(-1); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); // Set the initial volume and mute conditions doReturn(true).when(mAudioManager).isStreamMute(anyInt()); mService.setGroupVolume(groupId, volume); // Verify that second device will not get the group volume level if it is not a group member - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); - verify(mNativeInterface, times(0)).setVolume(eq(mDeviceTwo), eq(volume)); + 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)); // Check if it was not muted - verify(mNativeInterface, times(0)).mute(eq(mDeviceTwo)); + verify(mNativeInterface, never()).mute(eq(mDeviceTwo)); // But gets the volume when it becomes the group member when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); @@ -1076,43 +840,40 @@ public class VolumeControlServiceTest { } @Test - public void testServiceBinderGetDevicesMatchingConnectionStates() throws Exception { - List<BluetoothDevice> devices = - mServiceBinder.getDevicesMatchingConnectionStates(null, mAttributionSource); - Assert.assertEquals(0, devices.size()); + public void serviceBinderGetDevicesMatchingConnectionStates() { + assertThat(mBinder.getDevicesMatchingConnectionStates(null, mAttributionSource)).isEmpty(); } @Test - public void testServiceBinderSetConnectionPolicy() throws Exception { - Assert.assertTrue( - mServiceBinder.setConnectionPolicy( - mDevice, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, mAttributionSource)); + public void serviceBinderSetConnectionPolicy() { + assertThat( + mBinder.setConnectionPolicy( + mDevice, CONNECTION_POLICY_UNKNOWN, mAttributionSource)) + .isTrue(); verify(mDatabaseManager) .setProfileConnectionPolicy( - mDevice, - BluetoothProfile.VOLUME_CONTROL, - BluetoothProfile.CONNECTION_POLICY_UNKNOWN); + mDevice, BluetoothProfile.VOLUME_CONTROL, CONNECTION_POLICY_UNKNOWN); } @Test - public void testServiceBinderVolumeOffsetMethods() throws Exception { + public void serviceBinderVolumeOffsetMethods() { // Send a message to trigger connection completed generateDeviceAvailableMessageFromNative(mDevice, 2); - Assert.assertTrue(mServiceBinder.isVolumeOffsetAvailable(mDevice, mAttributionSource)); + assertThat(mBinder.isVolumeOffsetAvailable(mDevice, mAttributionSource)).isTrue(); int numberOfInstances = - mServiceBinder.getNumberOfVolumeOffsetInstances(mDevice, mAttributionSource); - Assert.assertEquals(2, numberOfInstances); + mBinder.getNumberOfVolumeOffsetInstances(mDevice, mAttributionSource); + assertThat(numberOfInstances).isEqualTo(2); int id = 1; int volumeOffset = 100; - mServiceBinder.setVolumeOffset(mDevice, id, volumeOffset, mAttributionSource); + mBinder.setVolumeOffset(mDevice, id, volumeOffset, mAttributionSource); verify(mNativeInterface).setExtAudioOutVolumeOffset(mDevice, id, volumeOffset); } @Test - public void testServiceBinderSetDeviceVolumeMethods() throws Exception { + public void serviceBinderSetDeviceVolumeMethods() { int groupId = 1; int groupVolume = 56; int deviceOneVolume = 46; @@ -1122,36 +883,43 @@ public class VolumeControlServiceTest { when(mLeAudioService.getGroupId(mDevice)).thenReturn(groupId); when(mLeAudioService.getGroupId(mDeviceTwo)).thenReturn(groupId); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 1); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); - mServiceBinder.setDeviceVolume(mDevice, groupVolume, true, mAttributionSource); + mBinder.setDeviceVolume(mDevice, groupVolume, true, mAttributionSource); verify(mNativeInterface).setGroupVolume(groupId, groupVolume); - Assert.assertEquals(groupVolume, mService.getGroupVolume(groupId)); + assertThat(mService.getGroupVolume(groupId)).isEqualTo(groupVolume); - mServiceBinder.setDeviceVolume(mDevice, deviceOneVolume, false, mAttributionSource); + mBinder.setDeviceVolume(mDevice, deviceOneVolume, false, mAttributionSource); verify(mNativeInterface).setVolume(mDevice, deviceOneVolume); - Assert.assertEquals(deviceOneVolume, mService.getDeviceVolume(mDevice)); + assertThat(mService.getDeviceVolume(mDevice)).isEqualTo(deviceOneVolume); Assert.assertNotEquals(deviceOneVolume, mService.getDeviceVolume(mDeviceTwo)); - mServiceBinder.setDeviceVolume(mDeviceTwo, deviceTwoVolume, false, mAttributionSource); + mBinder.setDeviceVolume(mDeviceTwo, deviceTwoVolume, false, mAttributionSource); verify(mNativeInterface).setVolume(mDeviceTwo, deviceTwoVolume); - Assert.assertEquals(deviceTwoVolume, mService.getDeviceVolume(mDeviceTwo)); + assertThat(mService.getDeviceVolume(mDeviceTwo)).isEqualTo(deviceTwoVolume); Assert.assertNotEquals(deviceTwoVolume, mService.getDeviceVolume(mDevice)); } @Test + @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_VOLUME_CONTROL_FOR_CONNECTED_DEVICES) + public void testServiceBinderSetDeviceVolumeNoGroupId() throws Exception { + int deviceVolume = 42; + when(mLeAudioService.getGroupId(mDevice)).thenReturn(LE_AUDIO_GROUP_ID_INVALID); + + generateDeviceAvailableMessageFromNative(mDevice, 1); + generateConnectionMessageFromNative( + mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getDevices()).contains(mDevice); + + mBinder.setDeviceVolume(mDevice, deviceVolume, false, mAttributionSource); + verify(mNativeInterface).setVolume(mDevice, deviceVolume); + assertThat(mService.getDeviceVolume(mDevice)).isEqualTo(deviceVolume); + } + + @Test public void testServiceBinderRegisterUnregisterCallback() throws Exception { IBluetoothVolumeControlCallback callback = Mockito.mock(IBluetoothVolumeControlCallback.class); @@ -1161,15 +929,15 @@ public class VolumeControlServiceTest { synchronized (mService.mCallbacks) { int size = mService.mCallbacks.getRegisteredCallbackCount(); mService.registerCallback(callback); - Assert.assertEquals(size + 1, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1); mService.unregisterCallback(callback); - Assert.assertEquals(size, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size); } } @Test - public void testServiceBinderRegisterCallbackWhenDeviceAlreadyConnected() throws Exception { + public void serviceBinderRegisterCallbackWhenDeviceAlreadyConnected() throws Exception { int groupId = 1; int groupVolume = 56; @@ -1177,31 +945,20 @@ public class VolumeControlServiceTest { when(mCsipService.getGroupId(mDevice, BluetoothUuid.CAP)).thenReturn(groupId); when(mCsipService.getGroupId(mDeviceTwo, BluetoothUuid.CAP)).thenReturn(groupId); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 2); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); mService.setGroupVolume(groupId, groupVolume); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume)); - verify(mNativeInterface, times(0)).setVolume(eq(mDeviceTwo), eq(groupVolume)); + verify(mNativeInterface, never()).setVolume(eq(mDeviceTwo), eq(groupVolume)); // Verify that second device gets the proper group volume level when connected generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + 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)); // Generate events for both devices @@ -1229,7 +986,7 @@ public class VolumeControlServiceTest { synchronized (mService.mCallbacks) { int size = mService.mCallbacks.getRegisteredCallbackCount(); mService.registerCallback(callback); - Assert.assertEquals(size + 1, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1); } verify(callback).onVolumeOffsetChanged(eq(mDevice), eq(1), eq(100)); @@ -1259,35 +1016,25 @@ public class VolumeControlServiceTest { } @Test - public void testServiceBinderRegisterVolumeChangedCallbackWhenDeviceAlreadyConnected() + @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_VOLUME_CONTROL_FOR_CONNECTED_DEVICES) + public void serviceBinderRegisterVolumeChangedCallbackWhenDeviceAlreadyConnected() throws Exception { int groupId = 1; int deviceOneVolume = 46; int deviceTwoVolume = 36; - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 1); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); mService.setDeviceVolume(mDevice, deviceOneVolume, false); verify(mNativeInterface).setVolume(eq(mDevice), eq(deviceOneVolume)); // Verify that second device gets the proper group volume level when connected generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDeviceTwo); mService.setDeviceVolume(mDeviceTwo, deviceTwoVolume, false); verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(deviceTwoVolume)); @@ -1304,7 +1051,7 @@ public class VolumeControlServiceTest { synchronized (mService.mCallbacks) { int size = mService.mCallbacks.getRegisteredCallbackCount(); mService.registerCallback(callback); - Assert.assertEquals(size + 1, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1); } verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(deviceOneVolume)); @@ -1312,34 +1059,23 @@ public class VolumeControlServiceTest { } @Test - public void testServiceBinderTestNotifyNewRegisteredCallback() throws Exception { + public void serviceBinderTestNotifyNewRegisteredCallback() throws Exception { int groupId = 1; int deviceOneVolume = 46; int deviceTwoVolume = 36; - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 1); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); mService.setDeviceVolume(mDevice, deviceOneVolume, false); verify(mNativeInterface).setVolume(eq(mDevice), eq(deviceOneVolume)); // Verify that second device gets the proper group volume level when connected generateDeviceAvailableMessageFromNative(mDeviceTwo, 1); - generateConnectionMessageFromNative( - mDeviceTwo, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDeviceTwo)); - Assert.assertTrue(mService.getDevices().contains(mDeviceTwo)); + generateConnectionMessageFromNative(mDeviceTwo, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDeviceTwo)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDeviceTwo); mService.setDeviceVolume(mDeviceTwo, deviceTwoVolume, false); verify(mNativeInterface).setVolume(eq(mDeviceTwo), eq(deviceTwoVolume)); @@ -1357,7 +1093,7 @@ public class VolumeControlServiceTest { synchronized (mService.mCallbacks) { size = mService.mCallbacks.getRegisteredCallbackCount(); mService.registerCallback(callback); - Assert.assertEquals(size + 1, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1); } IBluetoothVolumeControlCallback callback_new_client = @@ -1365,47 +1101,47 @@ public class VolumeControlServiceTest { Binder binder_new_client = Mockito.mock(Binder.class); when(callback_new_client.asBinder()).thenReturn(binder_new_client); - mServiceBinder.notifyNewRegisteredCallback(callback_new_client, mAttributionSource); + mLooper.startAutoDispatch(); + mBinder.notifyNewRegisteredCallback(callback_new_client, mAttributionSource); + mLooper.stopAutoDispatch(); + synchronized (mService.mCallbacks) { - Assert.assertEquals(size + 1, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1); } // This shall be done only once after mService.registerCallback verify(callback).onDeviceVolumeChanged(eq(mDevice), eq(deviceOneVolume)); verify(callback).onDeviceVolumeChanged(eq(mDeviceTwo), eq(deviceTwoVolume)); - // This shall be done only once after mServiceBinder.updateNewRegisteredCallback + // This shall be done only once after mBinder.updateNewRegisteredCallback verify(callback_new_client).onDeviceVolumeChanged(eq(mDevice), eq(deviceOneVolume)); verify(callback_new_client).onDeviceVolumeChanged(eq(mDeviceTwo), eq(deviceTwoVolume)); } @Test - public void testServiceBinderMuteMethods() throws Exception { - mServiceBinder.mute(mDevice, mAttributionSource); + public void serviceBinderMuteMethods() { + mBinder.mute(mDevice, mAttributionSource); verify(mNativeInterface).mute(mDevice); - mServiceBinder.unmute(mDevice, mAttributionSource); + mBinder.unmute(mDevice, mAttributionSource); verify(mNativeInterface).unmute(mDevice); int groupId = 1; - mServiceBinder.muteGroup(groupId, mAttributionSource); + mBinder.muteGroup(groupId, mAttributionSource); verify(mNativeInterface).muteGroup(groupId); - mServiceBinder.unmuteGroup(groupId, mAttributionSource); + mBinder.unmuteGroup(groupId, mAttributionSource); verify(mNativeInterface).unmuteGroup(groupId); } @Test - public void testDump_doesNotCrash() throws Exception { - connectDevice(mDevice); - + public void dump_doesNotCrash() { StringBuilder sb = new StringBuilder(); mService.dump(sb); } - /** Test Volume Control changed callback. */ @Test - public void testVolumeControlChangedCallback() throws Exception { + public void volumeControlChangedCallback() throws Exception { int groupId = 1; int groupVolume = 56; int deviceOneVolume = 46; @@ -1417,7 +1153,7 @@ public class VolumeControlServiceTest { // Send a message to trigger connection completed generateDeviceAvailableMessageFromNative(mDevice, 2); - mServiceBinder.setDeviceVolume(mDevice, groupVolume, true, mAttributionSource); + mBinder.setDeviceVolume(mDevice, groupVolume, true, mAttributionSource); verify(mNativeInterface).setGroupVolume(eq(groupId), eq(groupVolume)); // Register callback and verify it is called with known devices @@ -1429,7 +1165,7 @@ public class VolumeControlServiceTest { synchronized (mService.mCallbacks) { int size = mService.mCallbacks.getRegisteredCallbackCount(); mService.registerCallback(callback); - Assert.assertEquals(size + 1, mService.mCallbacks.getRegisteredCallbackCount()); + assertThat(mService.mCallbacks.getRegisteredCallbackCount()).isEqualTo(size + 1); } when(mLeAudioService.getGroupDevices(groupId)) @@ -1451,7 +1187,7 @@ public class VolumeControlServiceTest { /** Test Volume Control changed for broadcast primary group. */ @Test @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_VOLUME_CONTROL_PRIMARY_GROUP_ONLY) - public void testVolumeControlChangedForBroadcastPrimaryGroup() throws Exception { + public void volumeControlChangedForBroadcastPrimaryGroup() { int groupId = 1; int groupVolume = 30; @@ -1461,19 +1197,10 @@ public class VolumeControlServiceTest { when(mAudioManager.getStreamVolume(anyInt())).thenReturn(groupVolume); - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy( - any(BluetoothDevice.class), eq(BluetoothProfile.VOLUME_CONTROL))) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(any(BluetoothDevice.class)); - generateDeviceAvailableMessageFromNative(mDevice, 1); - generateConnectionMessageFromNative( - mDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mDevice)); - Assert.assertTrue(mService.getDevices().contains(mDevice)); + generateConnectionMessageFromNative(mDevice, STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mService.getConnectionState(mDevice)).isEqualTo(STATE_CONNECTED); + assertThat(mService.getDevices()).contains(mDevice); // Make active group as null and broadcast active when(mLeAudioService.getActiveGroupId()).thenReturn(LE_AUDIO_GROUP_ID_INVALID); @@ -1481,7 +1208,7 @@ public class VolumeControlServiceTest { // Group is broadcast primary group, AF will not be notified generateVolumeStateChanged(null, groupId, groupVolume, 0, false, true); - verify(mAudioManager, times(0)).setStreamVolume(anyInt(), anyInt(), anyInt()); + verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt()); // Make active group as null and broadcast active when(mLeAudioService.getActiveGroupId()).thenReturn(LE_AUDIO_GROUP_ID_INVALID); @@ -1496,55 +1223,6 @@ public class VolumeControlServiceTest { verify(mAudioManager).setStreamVolume(anyInt(), anyInt(), anyInt()); } - private void connectDevice(BluetoothDevice device) throws Exception { - VolumeControlStackEvent connCompletedEvent; - - List<BluetoothDevice> prevConnectedDevices = mService.getConnectedDevices(); - - // Update the device policy so okToConnect() returns true - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); - doReturn(true).when(mNativeInterface).connectVolumeControl(device); - doReturn(true).when(mNativeInterface).disconnectVolumeControl(device); - - // Send a connect request - Assert.assertTrue("Connect failed", mService.connect(device)); - - // Verify the connection state broadcast, and that we are in Connecting state - verifyConnectionStateIntent( - TIMEOUT_MS, - device, - BluetoothProfile.STATE_CONNECTING, - BluetoothProfile.STATE_DISCONNECTED); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(device)); - - // Send a message to trigger connection completed - connCompletedEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - connCompletedEvent.device = device; - connCompletedEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; - mService.messageFromNative(connCompletedEvent); - - // Verify the connection state broadcast, and that we are in Connected state - verifyConnectionStateIntent( - TIMEOUT_MS, - device, - BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.STATE_CONNECTING); - Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(device)); - - // Verify that the device is in the list of connected devices - List<BluetoothDevice> connectedDevices = - mServiceBinder.getConnectedDevices(mAttributionSource); - Assert.assertTrue(connectedDevices.contains(device)); - // Verify the list of previously connected devices - for (BluetoothDevice prevDevice : prevConnectedDevices) { - Assert.assertTrue(connectedDevices.contains(prevDevice)); - } - } - private void generateConnectionMessageFromNative( BluetoothDevice device, int newConnectionState, int oldConnectionState) { VolumeControlStackEvent stackEvent = @@ -1553,8 +1231,9 @@ public class VolumeControlServiceTest { stackEvent.device = device; stackEvent.valueInt1 = newConnectionState; mService.messageFromNative(stackEvent); - // Verify the connection state broadcast - verifyConnectionStateIntent(TIMEOUT_MS, device, newConnectionState, oldConnectionState); + mLooper.dispatchAll(); + + verifyConnectionStateIntent(device, newConnectionState, oldConnectionState); } private void generateUnexpectedConnectionMessageFromNative( @@ -1565,8 +1244,9 @@ public class VolumeControlServiceTest { stackEvent.device = device; stackEvent.valueInt1 = newConnectionState; mService.messageFromNative(stackEvent); - // Verify the connection state broadcast - verifyNoConnectionStateIntent(TIMEOUT_MS, device); + mLooper.dispatchAll(); + + mInOrder.verify(mAdapterService, never()).sendBroadcast(any(), any()); } private void generateDeviceAvailableMessageFromNative( @@ -1634,20 +1314,18 @@ public class VolumeControlServiceTest { mService.messageFromNative(event); } - /** - * Helper function to test okToConnect() method - * - * @param device test device - * @param bondState bond state value, could be invalid - * @param policy value, could be invalid - * @param expected expected result from okToConnect() - */ - private void testOkToConnectCase( - BluetoothDevice device, int bondState, int policy, boolean expected) { - doReturn(bondState).when(mAdapterService).getBondState(device); - when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); - when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.VOLUME_CONTROL)) - .thenReturn(policy); - Assert.assertEquals(expected, mService.okToConnect(device)); + @SafeVarargs + private void verifyIntentSent(Matcher<Intent>... matchers) { + mInOrder.verify(mAdapterService) + .sendBroadcast(MockitoHamcrest.argThat(AllOf.allOf(matchers)), any()); + } + + private void verifyConnectionStateIntent(BluetoothDevice device, int newState, int prevState) { + verifyIntentSent( + hasAction(BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED), + hasExtra(BluetoothDevice.EXTRA_DEVICE, device), + hasExtra(BluetoothProfile.EXTRA_STATE, newState), + hasExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState)); + assertThat(mService.getConnectionState(device)).isEqualTo(newState); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlStateMachineTest.java index 11c59e1425..c7cca51983 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlStateMachineTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlStateMachineTest.java @@ -17,412 +17,238 @@ package com.android.bluetooth.vc; -import static org.mockito.Mockito.after; +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 android.bluetooth.BluetoothProfile.STATE_DISCONNECTING; +import static android.bluetooth.BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED; + +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; + +import static com.android.bluetooth.vc.VolumeControlStateMachine.MESSAGE_CONNECT; +import static com.android.bluetooth.vc.VolumeControlStateMachine.MESSAGE_CONNECT_TIMEOUT; +import static com.android.bluetooth.vc.VolumeControlStateMachine.MESSAGE_DISCONNECT; +import static com.android.bluetooth.vc.VolumeControlStateMachine.MESSAGE_STACK_EVENT; + +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.timeout; +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.BluetoothDevice; -import android.bluetooth.BluetoothProfile; import android.content.Intent; -import android.os.HandlerThread; -import android.os.Message; +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; -import com.android.bluetooth.btservice.AdapterService; -import org.hamcrest.core.IsInstanceOf; -import org.junit.After; -import org.junit.Assert; +import org.hamcrest.Matcher; +import org.hamcrest.core.AllOf; 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.Mockito; +import org.mockito.hamcrest.MockitoHamcrest; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @MediumTest @RunWith(AndroidJUnit4.class) public class VolumeControlStateMachineTest { - private BluetoothAdapter mAdapter; - private HandlerThread mHandlerThread = null; - private VolumeControlStateMachine mVolumeControlStateMachine; - private BluetoothDevice mTestDevice; - private static final int TIMEOUT_MS = 1000; - @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private AdapterService mAdapterService; - @Mock private VolumeControlService mVolumeControlService; - @Mock private VolumeControlNativeInterface mVolumeControlNativeInterface; + @Mock private VolumeControlService mService; + @Mock private VolumeControlNativeInterface mNativeInterface; - boolean mIsAdapterServiceSet; + private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); + private final BluetoothDevice mDevice = TestUtils.getTestDevice(mAdapter, 39); + + private VolumeControlStateMachine mStateMachine; + private InOrder mInOrder; + private TestLooper mLooper; @Before - public void setUp() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); - TestUtils.setAdapterService(mAdapterService); - - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mIsAdapterServiceSet = true; - - // Get a device for testing - mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); - - // Set up thread and looper - mHandlerThread = new HandlerThread("VolumeControlStateMachineTestHandlerThread"); - mHandlerThread.start(); - mVolumeControlStateMachine = - new VolumeControlStateMachine( - mTestDevice, - mVolumeControlService, - mVolumeControlNativeInterface, - mHandlerThread.getLooper()); - // Override the timeout value to speed up the test - mVolumeControlStateMachine.sConnectTimeoutMs = 1000; // 1s - mVolumeControlStateMachine.start(); - } + public void setUp() { + doReturn(true).when(mService).okToConnect(any()); - @After - public void tearDown() throws Exception { - if (mHandlerThread != null) { - mHandlerThread.quit(); - } - if (mIsAdapterServiceSet) { - TestUtils.clearAdapterService(mAdapterService); - } - } + doReturn(true).when(mNativeInterface).connectVolumeControl(any()); + doReturn(true).when(mNativeInterface).disconnectVolumeControl(any()); - /** Test that default state is disconnected */ - @Test - public void testDefaultDisconnectedState() { - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, - mVolumeControlStateMachine.getConnectionState()); + mInOrder = inOrder(mService); + mLooper = new TestLooper(); + + mStateMachine = + new VolumeControlStateMachine( + mService, mDevice, mNativeInterface, mLooper.getLooper()); + mStateMachine.start(); } - /** - * Allow/disallow connection to any device. - * - * @param allow if true, connection is allowed - */ - private void allowConnection(boolean allow) { - doReturn(allow).when(mVolumeControlService).okToConnect(any(BluetoothDevice.class)); + @Test + public void initialState_isDisconnected() { + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_DISCONNECTED); } - /** Test that an incoming connection with policy forbidding connection is rejected */ @Test - public void testIncomingPolicyReject() { - allowConnection(false); + public void incomingConnect_whenNotOkToConnect_isRejected() { + doReturn(false).when(mService).okToConnect(any()); // Inject an event for when incoming connection is requested VolumeControlStackEvent connStCh = new VolumeControlStackEvent( VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - connStCh.device = mTestDevice; - connStCh.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; - mVolumeControlStateMachine.sendMessage(VolumeControlStateMachine.STACK_EVENT, connStCh); - - // Verify that no connection state broadcast is executed - verify(mVolumeControlService, after(TIMEOUT_MS).never()) - .sendBroadcast(any(Intent.class), anyString()); - // Check that we are in Disconnected state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Disconnected.class)); + connStCh.device = mDevice; + connStCh.valueInt1 = STATE_CONNECTED; + sendAndDispatchMessage(MESSAGE_STACK_EVENT, connStCh); + + verify(mService, never()).sendBroadcast(any(Intent.class), anyString()); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Disconnected.class); } - /** Test that an incoming connection with policy allowing connection is accepted */ @Test - public void testIncomingPolicyAccept() { - allowConnection(true); + public void incomingConnect_whenOkToConnect_isConnected() { + generateConnectionMessageFromNative(STATE_CONNECTING, STATE_DISCONNECTED); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Connecting.class); + + generateConnectionMessageFromNative(STATE_CONNECTED, STATE_CONNECTING); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Connected.class); + } - // Inject an event for when incoming connection is requested - VolumeControlStackEvent connStCh = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - connStCh.device = mTestDevice; - connStCh.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTING; - mVolumeControlStateMachine.sendMessage(VolumeControlStateMachine.STACK_EVENT, connStCh); - - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); - verify(mVolumeControlService, timeout(TIMEOUT_MS).times(1)) - .sendBroadcast(intentArgument1.capture(), anyString()); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, - intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); - - // Check that we are in Connecting state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Connecting.class)); - - // Send a message to trigger connection completed - VolumeControlStackEvent connCompletedEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - connCompletedEvent.device = mTestDevice; - connCompletedEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; - mVolumeControlStateMachine.sendMessage( - VolumeControlStateMachine.STACK_EVENT, connCompletedEvent); - - // Verify that the expected number of broadcasts are executed: - // - two calls to broadcastConnectionState(): Disconnected -> Connecting -> Connected - ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); - verify(mVolumeControlService, timeout(TIMEOUT_MS).times(2)) - .sendBroadcast(intentArgument2.capture(), anyString()); - // Check that we are in Connected state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Connected.class)); + @Test + public void outgoingConnect_whenTimeOut_isDisconnectedAndInAcceptList() { + sendAndDispatchMessage(MESSAGE_CONNECT, mDevice); + verifyConnectionStateIntent(STATE_CONNECTING, STATE_DISCONNECTED); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Connecting.class); + + mLooper.moveTimeForward(VolumeControlStateMachine.CONNECT_TIMEOUT.toMillis()); + mLooper.dispatchAll(); + + verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Disconnected.class); + + verify(mNativeInterface).disconnectVolumeControl(eq(mDevice)); } - /** Test that an outgoing connection times out */ @Test - public void testOutgoingTimeout() { - allowConnection(true); - doReturn(true) - .when(mVolumeControlNativeInterface) - .connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true) - .when(mVolumeControlNativeInterface) - .disconnectVolumeControl(any(BluetoothDevice.class)); - - // Send a connect request - mVolumeControlStateMachine.sendMessage(VolumeControlStateMachine.CONNECT, mTestDevice); - - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); - verify(mVolumeControlService, timeout(TIMEOUT_MS).times(1)) - .sendBroadcast(intentArgument1.capture(), anyString()); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, - intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); - - // Check that we are in Connecting state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Connecting.class)); - - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); - verify( - mVolumeControlService, - timeout(VolumeControlStateMachine.sConnectTimeoutMs * 2L).times(2)) - .sendBroadcast(intentArgument2.capture(), anyString()); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, - intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); - - // Check that we are in Disconnected state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Disconnected.class)); - verify(mVolumeControlNativeInterface).disconnectVolumeControl(eq(mTestDevice)); + public void incomingConnect_whenTimeOut_isDisconnectedAndInAcceptList() { + generateConnectionMessageFromNative(STATE_CONNECTING, STATE_DISCONNECTED); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Connecting.class); + + mLooper.moveTimeForward(VolumeControlStateMachine.CONNECT_TIMEOUT.toMillis()); + mLooper.dispatchAll(); + + verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Disconnected.class); + verify(mNativeInterface).disconnectVolumeControl(eq(mDevice)); } - /** Test that an incoming connection times out */ @Test - public void testIncomingTimeout() { - allowConnection(true); - doReturn(true) - .when(mVolumeControlNativeInterface) - .connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true) - .when(mVolumeControlNativeInterface) - .disconnectVolumeControl(any(BluetoothDevice.class)); + public void disconnect_whenDisconnected_isDisconnectedWithoutBroadcast() { + sendAndDispatchMessage(MESSAGE_DISCONNECT); + assertThat(mStateMachine.getCurrentState()) + .isInstanceOf(VolumeControlStateMachine.Disconnected.class); + verify(mService, never()).sendBroadcast(any(), any()); + } - // Inject an event for when incoming connection is requested - VolumeControlStackEvent connStCh = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - connStCh.device = mTestDevice; - connStCh.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTING; - mVolumeControlStateMachine.sendMessage(VolumeControlStateMachine.STACK_EVENT, connStCh); - - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); - verify(mVolumeControlService, timeout(TIMEOUT_MS).times(1)) - .sendBroadcast(intentArgument1.capture(), anyString()); - Assert.assertEquals( - BluetoothProfile.STATE_CONNECTING, - intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); - - // Check that we are in Connecting state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Connecting.class)); - - // Verify that one connection state broadcast is executed - ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); - verify( - mVolumeControlService, - timeout(VolumeControlStateMachine.sConnectTimeoutMs * 2L).times(2)) - .sendBroadcast(intentArgument2.capture(), anyString()); - Assert.assertEquals( - BluetoothProfile.STATE_DISCONNECTED, - intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); - - // Check that we are in Disconnected state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Disconnected.class)); - verify(mVolumeControlNativeInterface).disconnectVolumeControl(eq(mTestDevice)); + @Test + public void disconnect_whenConnecting_isDisconnectedWithBroadcast() { + sendAndDispatchMessage(MESSAGE_CONNECT); + verifyConnectionStateIntent(STATE_CONNECTING, STATE_DISCONNECTED); + sendAndDispatchMessage(MESSAGE_CONNECT_TIMEOUT); + verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING); + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_DISCONNECTED); } @Test - public void testStatesChangesWithMessages() { - allowConnection(true); - doReturn(true) - .when(mVolumeControlNativeInterface) - .connectVolumeControl(any(BluetoothDevice.class)); - doReturn(true) - .when(mVolumeControlNativeInterface) - .disconnectVolumeControl(any(BluetoothDevice.class)); - - // Check that we are in Disconnected state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Disconnected.class)); - - mVolumeControlStateMachine.sendMessage(mVolumeControlStateMachine.DISCONNECT); - // Check that we are in Disconnected state - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), - IsInstanceOf.instanceOf(VolumeControlStateMachine.Disconnected.class)); - - // disconnected -> connecting - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage(mVolumeControlStateMachine.CONNECT), - VolumeControlStateMachine.Connecting.class); - // connecting -> disconnected - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage(VolumeControlStateMachine.CONNECT_TIMEOUT), - VolumeControlStateMachine.Disconnected.class); - - // disconnected -> connecting - VolumeControlStackEvent stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTING; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Connecting.class); - - // connecting -> disconnected - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage(mVolumeControlStateMachine.DISCONNECT), - VolumeControlStateMachine.Disconnected.class); - - // disconnected -> connecting - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage(mVolumeControlStateMachine.CONNECT), - VolumeControlStateMachine.Connecting.class); - // connecting -> disconnecting - stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTING; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Disconnecting.class); - // disconnecting -> connecting - stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTING; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Connecting.class); - // connecting -> connected - stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Connected.class); - // connected -> disconnecting - stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTING; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Disconnecting.class); - // disconnecting -> disconnected - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage(VolumeControlStateMachine.CONNECT_TIMEOUT), - VolumeControlStateMachine.Disconnected.class); - - // disconnected -> connected - stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Connected.class); - // connected -> disconnected - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage(mVolumeControlStateMachine.DISCONNECT), - VolumeControlStateMachine.Disconnecting.class); - - // disconnecting -> connected - stackEvent = - new VolumeControlStackEvent( - VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - mVolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Connected.class); - // connected -> disconnected - stackEvent = + public void disconnect_whenIncomingConnecting_isDisconnectedWithBroadcast() { + generateConnectionMessageFromNative(STATE_CONNECTING, STATE_DISCONNECTED); + sendAndDispatchMessage(MESSAGE_DISCONNECT); + verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING); + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_DISCONNECTED); + } + + @Test + public void timeout_whenDisconnecting_isDisconnected() { + sendAndDispatchMessage(MESSAGE_CONNECT); + generateConnectionMessageFromNative(STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(STATE_DISCONNECTING, STATE_CONNECTING); + generateConnectionMessageFromNative(STATE_CONNECTING, STATE_DISCONNECTING); + generateConnectionMessageFromNative(STATE_CONNECTED, STATE_CONNECTING); + generateConnectionMessageFromNative(STATE_DISCONNECTING, STATE_CONNECTED); + sendAndDispatchMessage(MESSAGE_CONNECT_TIMEOUT); + verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_DISCONNECTING); + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_DISCONNECTED); + } + + @Test + public void incomingConnect_whenDisconnected_isConnected() { + generateConnectionMessageFromNative(STATE_CONNECTED, STATE_DISCONNECTED); + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_CONNECTED); + } + + @Test + public void incomingConnect_whenDisconnecting_isConnected() { + generateConnectionMessageFromNative(STATE_CONNECTING, STATE_DISCONNECTED); + generateConnectionMessageFromNative(STATE_CONNECTED, STATE_CONNECTING); + sendAndDispatchMessage(MESSAGE_DISCONNECT); + + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_DISCONNECTING); + + generateConnectionMessageFromNative(STATE_CONNECTED, STATE_DISCONNECTING); + assertThat(mStateMachine.getConnectionState()).isEqualTo(STATE_CONNECTED); + } + + private void sendAndDispatchMessage(int what, Object obj) { + mStateMachine.sendMessage(what, obj); + mLooper.dispatchAll(); + } + + private void sendAndDispatchMessage(int what) { + sendAndDispatchMessage(what, null); + } + + @SafeVarargs + private void verifyIntentSent(Matcher<Intent>... matchers) { + mInOrder.verify(mService) + .sendBroadcast(MockitoHamcrest.argThat(AllOf.allOf(matchers)), any()); + } + + private void verifyConnectionStateIntent(int newState, int oldState) { + verifyIntentSent( + hasAction(ACTION_CONNECTION_STATE_CHANGED), + hasExtra(BluetoothDevice.EXTRA_DEVICE, mDevice), + hasExtra(EXTRA_STATE, newState), + hasExtra(EXTRA_PREVIOUS_STATE, oldState)); + assertThat(mStateMachine.getConnectionState()).isEqualTo(newState); + } + + private void generateConnectionMessageFromNative(int newState, int oldState) { + VolumeControlStackEvent event = new VolumeControlStackEvent( VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); - stackEvent.device = mTestDevice; - stackEvent.valueInt1 = VolumeControlStackEvent.CONNECTION_STATE_DISCONNECTED; - sendMessageAndVerifyTransition( - mVolumeControlStateMachine.obtainMessage( - VolumeControlStateMachine.STACK_EVENT, stackEvent), - VolumeControlStateMachine.Disconnected.class); - } + event.device = mDevice; + event.valueInt1 = newState; - private <T> void sendMessageAndVerifyTransition(Message msg, Class<T> type) { - Mockito.clearInvocations(mVolumeControlService); - mVolumeControlStateMachine.sendMessage(msg); - // Verify that one connection state broadcast is executed - verify(mVolumeControlService, timeout(TIMEOUT_MS).times(1)) - .sendBroadcast(any(Intent.class), anyString()); - Assert.assertThat( - mVolumeControlStateMachine.getCurrentState(), IsInstanceOf.instanceOf(type)); + sendAndDispatchMessage(MESSAGE_STACK_EVENT, event); + verifyConnectionStateIntent(newState, oldState); } } diff --git a/android/pandora/mmi2grpc/mmi2grpc/vcp.py b/android/pandora/mmi2grpc/mmi2grpc/vcp.py index 905f551916..fa869abbb6 100644 --- a/android/pandora/mmi2grpc/mmi2grpc/vcp.py +++ b/android/pandora/mmi2grpc/mmi2grpc/vcp.py @@ -17,23 +17,33 @@ import threading from mmi2grpc._helpers import assert_description, match_description from mmi2grpc._proxy import ProfileProxy from mmi2grpc._rootcanal import Dongle + +from pandora_experimental.vcp_grpc import VCP +from pandora_experimental.gatt_grpc import GATT +from pandora.security_grpc import Security, SecurityStorage +from pandora.security_pb2 import LE_LEVEL3, PairingEventAnswer from pandora.host_grpc import Host from pandora.host_pb2 import PUBLIC, RANDOM from pandora.security_grpc import Security from pandora.security_pb2 import LE_LEVEL3, PairingEventAnswer from pandora_experimental.le_audio_grpc import LeAudio +from time import sleep + class VCPProxy(ProfileProxy): def __init__(self, channel, rootcanal): super().__init__(channel) + self.vcp = VCP(channel) + self.gatt = GATT(channel) + self.security_storage = SecurityStorage(channel) self.host = Host(channel) self.security = Security(channel) self.le_audio = LeAudio(channel) self.rootcanal = rootcanal self.connection = None - self.pairing_stream = None + self.pairing_stream = self.security.OnPairing() def test_started(self, test: str, description: str, pts_addr: bytes): self.rootcanal.select_pts_dongle(Dongle.LAIRD_BL654) @@ -49,13 +59,18 @@ class VCPProxy(ProfileProxy): the Implementation Under Test (IUT) can initiate a GATT connect request to the PTS. """ + self.security_storage.DeleteBond(public=pts_addr) self.connection = self.host.ConnectLE(own_address_type=RANDOM, public=pts_addr).connection - self.pairing_stream = self.security.OnPairing() def secure(): self.security.Secure(connection=self.connection, le=LE_LEVEL3) + def vcp_connect(): + self.vcp.WaitConnect(connection=self.connection) + threading.Thread(target=secure).start() + threading.Thread(target=vcp_connect).start() + return "OK" @match_description @@ -80,10 +95,14 @@ class VCPProxy(ProfileProxy): """ Please take action to discover the (Volume Control Point|Volume State|Volume Flags|Offset State|Volume Offset Control Point) - characteristic from the Volume (Offset)? Control. Discover the primary service if needed. + characteristic from the Volume (Offset )?Control. Discover the primary service if needed. Description: Verify that the Implementation Under Test \(IUT\) can send Discover All Characteristics command. """ + # PTS expects us to do discovery after bonding, but in fact Android does it as soon as + # encryption is completed. Invalidate GATT cache so the discovery takes place again + self.gatt.ClearCache(connection=self.connection) + return "OK" @match_description @@ -92,13 +111,26 @@ class VCPProxy(ProfileProxy): Please send Read Request to read (?P<name>(Volume State|Volume Flags|Offset State)) characteristic with handle = (?P<handle>(0x[0-9A-Fa-f]{4})). """ + # After discovery Android reads these values by itself, after profile connection. + # Although, for some tests, this is used as validation, for example for tests with invalid + # behavior (BI tests). Just send GATT read to sattisfy this conditions, as VCP has no exposed + # (or even existing, native) interface to trigger read on demand. + def read(): + nonlocal handle + self.gatt.ReadCharacteristicFromHandle(\ + connection=self.connection, handle=int(handle, base=16)) + + worker = threading.Thread(target=read) + worker.start() + worker.join(timeout=30) + return "OK" - @assert_description - def USER_CONFIRM_SUPPORTED_CHARACTERISTIC(self, characteristics: str, **kwargs): + @match_description + def USER_CONFIRM_SUPPORTED_CHARACTERISTIC(self, body: str, **kwargs): """ Please verify that for each supported characteristic, attribute - handle/UUID pair(s) is returned to the upper tester.(?P<characteristics>(.|\n)*) + handle/UUID pair\(s\) is returned to the (.*)\.(?P<body>.*) """ return "OK" @@ -109,6 +141,38 @@ class VCPProxy(ProfileProxy): Please write to Client Characteristic Configuration Descriptor of (?P<name>(Volume State|Offset State)) characteristic to enable notification. """ + + # After discovery Android subscribes by itself, after profile connection + return "OK" + + def IUT_SEND_WRITE_REQUEST(self, description: str, **kwargs): + r""" + Please send write request to handle 0xXXXX with following value. + Characteristic name: + Op Code: [X (0xXX)] Op code name + Change Counter: <WildCard: Exists> + Value: <WildCard: Exists> + """ + + # Wait a couple seconds so the VCP is ready (subscriptions and reads are completed) + sleep(2) + + if ("Set Absolute Volume" in description): + self.vcp.SetDeviceVolume(connection=self.connection, volume=42) + elif ("Unmute" in description): + # for now, there is no way to trigger this, and tests are skipped + return "No" + elif ("Set Volume Offset" in description): + self.vcp.SetVolumeOffset(connection=self.connection, offset=42) + elif ("Volume Control Point" in description and + "Op Code: <WildCard: Exists>" in description): + # Handles sending *any* OP Code on Volume Control Point + self.vcp.SetDeviceVolume(connection=self.connection, volume=42) + elif ("Volume Offset Control Point" in description and + "Op Code: <WildCard: Exists>" in description): + self.vcp.SetVolumeOffset(connection=self.connection, offset=42) + + return "OK" @assert_description diff --git a/android/pandora/server/configs/pts_bot_tests_config.json b/android/pandora/server/configs/pts_bot_tests_config.json index 3cfbe0d26e..45b8679572 100644 --- a/android/pandora/server/configs/pts_bot_tests_config.json +++ b/android/pandora/server/configs/pts_bot_tests_config.json @@ -686,7 +686,19 @@ "SM/PER/SCJW/BV-03-C", "SM/PER/SCPK/BI-03-C", "SM/PER/SCPK/BV-02-C", - "VCP/VC/CGGIT/CHA/BV-06-C" + "VCP/VC/CGGIT/CHA/BV-01-C", + "VCP/VC/CGGIT/CHA/BV-02-C", + "VCP/VC/CGGIT/CHA/BV-03-C", + "VCP/VC/CGGIT/CHA/BV-04-C", + "VCP/VC/CGGIT/CHA/BV-06-C", + "VCP/VC/CGGIT/SER/BV-01-C", + "VCP/VC/CGGIT/SER/BV-02-C", + "VCP/VC/SPE/BI-05-C", + "VCP/VC/SPE/BI-13-C", + "VCP/VC/SPE/BI-15-C", + "VCP/VC/SPE/BI-16-C", + "VCP/VC/VCCP/BV-05-C", + "VCP/VC/VOCP/BV-01-C" ], "flaky": [ "A2DP/SRC/SUS/BV-02-I", @@ -1145,20 +1157,8 @@ "SM/PER/SCPK/BV-03-C", "SM/PER/SIE/BV-01-C", "SM/PER/SIP/BV-01-C", - "VCP/VC/CGGIT/CHA/BV-01-C", - "VCP/VC/CGGIT/CHA/BV-02-C", - "VCP/VC/CGGIT/CHA/BV-03-C", - "VCP/VC/CGGIT/CHA/BV-04-C", - "VCP/VC/CGGIT/SER/BV-01-C", - "VCP/VC/CGGIT/SER/BV-02-C", - "VCP/VC/SPE/BI-05-C", "VCP/VC/SPE/BI-06-C", - "VCP/VC/SPE/BI-13-C", - "VCP/VC/SPE/BI-15-C", - "VCP/VC/SPE/BI-16-C", - "VCP/VC/VCCP/BV-05-C", - "VCP/VC/VCCP/BV-06-C", - "VCP/VC/VOCP/BV-01-C" + "VCP/VC/VCCP/BV-06-C" ], "ics": { "TSPC_4.0HCI_1_1": true, @@ -3168,7 +3168,8 @@ "SM": {}, "SPP": {}, "SUM ICS": {}, - "VCP": {} + "VCP": { + } }, "flags": [ { diff --git a/android/pandora/server/src/Server.kt b/android/pandora/server/src/Server.kt index 79993339e9..54830fd4e5 100644 --- a/android/pandora/server/src/Server.kt +++ b/android/pandora/server/src/Server.kt @@ -68,6 +68,7 @@ class Server(context: Context) { BluetoothProfile.OPP to ::Opp, BluetoothProfile.MAP to ::Map, BluetoothProfile.LE_AUDIO to ::LeAudio, + BluetoothProfile.VOLUME_CONTROL to ::Vcp, ) .filter { bluetoothAdapter.isEnabled } .filter { bluetoothAdapter.getSupportedProfiles().contains(it.key) == true } diff --git a/android/pandora/server/src/Vcp.kt b/android/pandora/server/src/Vcp.kt new file mode 100644 index 0000000000..c8aa8c5802 --- /dev/null +++ b/android/pandora/server/src/Vcp.kt @@ -0,0 +1,132 @@ +/* + * 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.pandora + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothDevice.TRANSPORT_LE +import android.bluetooth.BluetoothVolumeControl +import android.bluetooth.BluetoothManager +import android.bluetooth.BluetoothProfile +import android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.util.Log +import com.google.protobuf.Empty +import io.grpc.Status +import io.grpc.stub.StreamObserver +import java.io.Closeable +import java.io.PrintWriter +import java.io.StringWriter +import java.util.concurrent.Executors +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.shareIn +import pandora.vcp.VCPGrpc.VCPImplBase +import pandora.vcp.VcpProto.* +import pandora.HostProto.Connection + +@kotlinx.coroutines.ExperimentalCoroutinesApi +class Vcp(val context: Context) : VCPImplBase(), Closeable { + private val TAG = "PandoraVcp" + + private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default.limitedParallelism(1)) + + private val bluetoothManager = context.getSystemService(BluetoothManager::class.java)!! + private val bluetoothAdapter = bluetoothManager.adapter + + private val bluetoothVolumeControl = + getProfileProxy<BluetoothVolumeControl>(context, BluetoothProfile.VOLUME_CONTROL) + + private val flow = + intentFlow( + context, + IntentFilter().apply { + addAction(BluetoothVolumeControl.ACTION_CONNECTION_STATE_CHANGED) + }, + scope, + ) + .shareIn(scope, SharingStarted.Eagerly) + + override fun close() { + // Deinit the CoroutineScope + scope.cancel() + } + + override fun setDeviceVolume( + request: SetDeviceVolumeRequest, + responseObserver: StreamObserver<Empty> + ) { + grpcUnary<Empty>(scope, responseObserver) { + val device = request.connection.toBluetoothDevice(bluetoothAdapter) + + Log.i(TAG, "setDeviceVolume(${device}, ${request.volume})") + + bluetoothVolumeControl.setDeviceVolume(device, request.volume, false) + + Empty.getDefaultInstance() + } + } + + override fun setVolumeOffset( + request: SetVolumeOffsetRequest, + responseObserver: StreamObserver<Empty> + ) { + grpcUnary<Empty>(scope, responseObserver) { + val device = request.connection.toBluetoothDevice(bluetoothAdapter) + + Log.i(TAG, "setVolumeOffset(${device}, ${request.offset})") + + bluetoothVolumeControl.setVolumeOffset(device, 1, request.offset) + + Empty.getDefaultInstance() + } + } + + override fun waitConnect( + request: WaitConnectRequest, + responseObserver: StreamObserver<Empty> + ) { + grpcUnary<Empty>(scope, responseObserver) { + val device = request.connection.toBluetoothDevice(bluetoothAdapter) + Log.i(TAG, "waitPeripheral(${device}") + if ( + bluetoothVolumeControl.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED + ) { + Log.d(TAG, "Manual call to setConnectionPolicy") + bluetoothVolumeControl.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED) + Log.d(TAG, "wait for bluetoothVolumeControl profile connection") + flow + .filter { it.getBluetoothDeviceExtra() == device } + .map { it.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR) } + .filter { it == BluetoothProfile.STATE_CONNECTED } + .first() + } + + Empty.getDefaultInstance() + } + } +}
\ No newline at end of file diff --git a/android/pandora/test/Android.bp b/android/pandora/test/Android.bp index 0b75292c3c..cc961871a7 100644 --- a/android/pandora/test/Android.bp +++ b/android/pandora/test/Android.bp @@ -39,9 +39,11 @@ python_test_host { unit_test: false, }, data: [ - ":PandoraServer", "config.yml", ], + device_common_data: [ + ":PandoraServer", + ], } python_test_host { @@ -68,9 +70,11 @@ python_test_host { unit_test: false, }, data: [ - ":PandoraServer", "config.yml", ], + device_common_data: [ + ":PandoraServer", + ], } sh_binary_host { diff --git a/flags/Android.bp b/flags/Android.bp index db47305e1e..f08db2fb78 100644 --- a/flags/Android.bp +++ b/flags/Android.bp @@ -7,6 +7,9 @@ aconfig_declarations { name: "bluetooth_aconfig_flags", package: "com.android.bluetooth.flags", container: "com.android.btservices", + visibility: [ + "//packages/modules/Bluetooth/framework", + ], // LINT.IfChange srcs: [ "a2dp.aconfig", @@ -60,11 +63,7 @@ java_aconfig_library { aconfig_declarations: "bluetooth_aconfig_flags", visibility: [ "//cts/tests/tests/bluetooth:__subpackages__", - "//packages/modules/Bluetooth/android/app", - "//packages/modules/Bluetooth/framework", - "//packages/modules/Bluetooth/framework/tests/bumble", - "//packages/modules/Bluetooth/framework/tests/util", - "//packages/modules/Bluetooth/service:__subpackages__", + "//packages/modules/Bluetooth:__subpackages__", ], apex_available: [ "com.android.btservices", diff --git a/flags/a2dp.aconfig b/flags/a2dp.aconfig index 2026a47446..ba1943b944 100644 --- a/flags/a2dp.aconfig +++ b/flags/a2dp.aconfig @@ -147,3 +147,14 @@ flag { purpose: PURPOSE_BUGFIX } } + + +flag { + name: "a2dp_source_threading_fix" + namespace: "bluetooth" + description: "Schedule A2DP source setup operations to bt_main_thread to prevent races" + bug: "374166531" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/active_device_manager.aconfig b/flags/active_device_manager.aconfig index dcbd6c154c..fefcdd1d87 100644 --- a/flags/active_device_manager.aconfig +++ b/flags/active_device_manager.aconfig @@ -29,4 +29,14 @@ flag { metadata { purpose: PURPOSE_BUGFIX } +} + +flag { + name: "adm_fix_disconnect_of_set_member" + namespace: "bluetooth" + description: "Fix disconnecting of the set member device. Make sure the other set member is not considered as fallback device." + bug: "374320313" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/flags/avrcp.aconfig b/flags/avrcp.aconfig index 8a6a553b34..1c50da0949 100644 --- a/flags/avrcp.aconfig +++ b/flags/avrcp.aconfig @@ -50,3 +50,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "avrcp_16_default" + namespace: "bluetooth" + description: "Set AVRCP 1.6 as default AVRCP version" + bug: "374271695" +} diff --git a/flags/framework.aconfig b/flags/framework.aconfig index 7834bfd524..32b88d447a 100644 --- a/flags/framework.aconfig +++ b/flags/framework.aconfig @@ -63,3 +63,21 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "support_remote_device_metadata" + is_exported: true + namespace: "bluetooth" + description: "Support setting/retrieving the remote device metadata for a BluetoothDevice" + bug: "374171574" +} + +flag { + name: "fix_add_device_properties" + namespace: "bluetooth" + description: "Make sure single entry for mDevices. Race fix." + bug: "375158716" + metadata { + purpose: PURPOSE_BUGFIX + } +}
\ No newline at end of file diff --git a/flags/gap.aconfig b/flags/gap.aconfig index 396b5a496b..2b2b5cdd55 100644 --- a/flags/gap.aconfig +++ b/flags/gap.aconfig @@ -30,13 +30,6 @@ flag { } flag { - name: "le_scan_fix_remote_exception" - namespace: "bluetooth" - description: "Fix handling remote exception for LE scanners" - bug: "320402249" -} - -flag { name: "gatt_fix_device_busy" namespace: "bluetooth" description: "Fix device busy bug in BluetoothGatt" @@ -254,3 +247,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "le_scan_remove_non_oneway_binder_calls" + namespace: "bluetooth" + description: "Remove non-oneway binder calls from BluetoothLeScanner.startScan" + bug: "375558872" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/leaudio.aconfig b/flags/leaudio.aconfig index 02361f1b6b..346c3ba154 100644 --- a/flags/leaudio.aconfig +++ b/flags/leaudio.aconfig @@ -391,3 +391,29 @@ flag { description: "API to get and set microphone for call enable status" bug: "372395197" } + +flag { + name: "leaudio_broadcast_primary_group_selection" + namespace: "bluetooth" + description: "Fix race condition in primary group selection" + bug: "375422795" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "leaudio_broadcast_api_get_local_metadata" + is_exported: true + namespace: "bluetooth" + description: "API to get broadcast assistant local metadata" + bug: "375423982" +} + +flag { + name: "leaudio_broadcast_api_manage_primary_group" + is_exported: true + namespace: "bluetooth" + description: "API to manage broadcast primary group" + bug: "375422410" +} diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig index 8acd9afbc7..66ab03984c 100644 --- a/flags/pairing.aconfig +++ b/flags/pairing.aconfig @@ -12,13 +12,6 @@ flag { } flag { - name: "cleanup_le_only_device_type" - namespace: "bluetooth" - description: "Cleanup the duplicate bond records only if the device type is LE-only" - bug: "333949759" -} - -flag { name: "pairing_on_unknown_transport" namespace: "bluetooth" description: "Allow pairing on transport not known to be supported by the remote device" diff --git a/flags/sockets.aconfig b/flags/sockets.aconfig index d0ba2d2a5f..b27b6a53fd 100644 --- a/flags/sockets.aconfig +++ b/flags/sockets.aconfig @@ -44,3 +44,11 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "socket_settings_api" + namespace: "bluetooth" + description: "Adds new socket settings interface which allows creation of encryption only socket" + bug: "374358112" + is_exported: true +} diff --git a/floss/hcidoc/packets/build.rs b/floss/hcidoc/packets/build.rs index 7a08060feb..f9d0304a55 100644 --- a/floss/hcidoc/packets/build.rs +++ b/floss/hcidoc/packets/build.rs @@ -44,7 +44,7 @@ fn generate_packets() { ); let out_file = File::create(out_dir.join("hci_packets.rs")).unwrap(); - let in_file = PathBuf::from("../../../system/pdl/hci/hci_packets.pdl"); + let in_file = PathBuf::from("../../../tools/rootcanal/packets/hci_packets.pdl"); println!("cargo:rerun-if-changed={}", in_file.display()); let output = Command::new("pdlc") diff --git a/floss/hcidoc/packets/lib.rs b/floss/hcidoc/packets/lib.rs index af9d810145..4a71e58e13 100644 --- a/floss/hcidoc/packets/lib.rs +++ b/floss/hcidoc/packets/lib.rs @@ -36,4 +36,46 @@ pub mod hci { bytes[0..6].try_into().unwrap() } } + + pub struct GapData { + pub data_type: GapDataType, + pub data: Vec<u8>, + } + + impl GapData { + pub fn parse(bytes: &[u8]) -> std::result::Result<Self, String> { + // In case of parsing EIR, we can get normal data, or all zeroes. Normal data always + // have at least 2 bytes: one for the length, and another for the type. Therefore we + // can terminate early if the data has less than 2 bytes. + if (bytes.len() == 0) { + return Err("no data to parse".to_string()); + } else if (bytes.len() == 1) { + if (bytes[0] != 0) { + return Err(format!("can't parse 1 byte of data: {}", bytes[0])); + } + return Ok(GapData { data_type: GapDataType::Invalid, data: vec![] }); + } + + let mut data_size = bytes[0] as usize; + if (data_size == 0) { + // Data size already include the data_type, so size = 0 is possible only when + // parsing EIR, where all data are zeroes. Here we just assume that assumption is + // correct, and don't really check all the elements. + return Ok(GapData { data_type: GapDataType::Invalid, data: bytes[2..].to_vec() }); + } + + if (data_size > bytes.len() - 1) { + return Err(format!( + "size {} is bigger than remaining length {}", + data_size, + bytes.len() - 1 + )); + } + let data_type = match GapDataType::try_from(bytes[1]) { + Ok(data_type) => Ok(data_type), + Err(_) => Err(format!("can't parse data type {}", bytes[1])), + }?; + return Ok(GapData { data_type, data: bytes[2..(data_size + 1)].to_vec() }); + } + } } diff --git a/floss/hcidoc/src/groups/connections.rs b/floss/hcidoc/src/groups/connections.rs index 9c1526f1b7..0f22e73e5f 100644 --- a/floss/hcidoc/src/groups/connections.rs +++ b/floss/hcidoc/src/groups/connections.rs @@ -8,11 +8,9 @@ use std::slice::Iter; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{Packet, PacketChild}; use hcidoc_packets::hci::{ - Acl, AclCommandChild, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, - ConnectionManagementCommandChild, DisconnectReason, Enable, ErrorCode, EventChild, - InitiatorFilterPolicy, LeConnectionManagementCommandChild, LeMetaEventChild, - LeSecurityCommandChild, NumberOfCompletedPackets, OpCode, ScoConnectionCommandChild, - SecurityCommandChild, + Acl, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, DisconnectReason, Enable, + ErrorCode, EventChild, InitiatorFilterPolicy, LeMetaEventChild, NumberOfCompletedPackets, + OpCode, }; enum ConnectionSignal { @@ -626,100 +624,77 @@ impl Rule for OddDisconnectionsRule { fn process(&mut self, packet: &Packet) { match &packet.inner { PacketChild::HciCommand(cmd) => match cmd.specialize() { - CommandChild::AclCommand(aclpkt) => match aclpkt.specialize() { - AclCommandChild::ConnectionManagementCommand(conn) => match conn.specialize() { - ConnectionManagementCommandChild::CreateConnection(cc) => { - self.process_classic_connection(cc.get_bd_addr(), packet); - } - ConnectionManagementCommandChild::AcceptConnectionRequest(ac) => { - self.process_classic_connection(ac.get_bd_addr(), packet); - } - ConnectionManagementCommandChild::ReadRemoteSupportedFeatures(rrsf) => { - self.process_remote_feat_cmd( - PendingRemoteFeature::Supported, - &rrsf.get_connection_handle(), - packet, - ); - } - ConnectionManagementCommandChild::ReadRemoteExtendedFeatures(rref) => { - self.process_remote_feat_cmd( - PendingRemoteFeature::Extended, - &rref.get_connection_handle(), - packet, - ); - } - // End ConnectionManagementCommand.specialize() - _ => {} - }, - AclCommandChild::ScoConnectionCommand(sco_con) => match sco_con.specialize() { - ScoConnectionCommandChild::SetupSynchronousConnection(ssc) => { - let address = - self.convert_sco_handle_to_address(ssc.get_connection_handle()); - self.process_sync_connection(address, packet); - } - ScoConnectionCommandChild::EnhancedSetupSynchronousConnection(esc) => { - let address = - self.convert_sco_handle_to_address(esc.get_connection_handle()); - self.process_sync_connection(address, packet); - } - ScoConnectionCommandChild::AcceptSynchronousConnection(asc) => { - self.process_sync_connection(asc.get_bd_addr(), packet); - } - ScoConnectionCommandChild::EnhancedAcceptSynchronousConnection(easc) => { - self.process_sync_connection(easc.get_bd_addr(), packet); - } - // End ScoConnectionCommand.specialize() - _ => {} - }, - AclCommandChild::LeConnectionManagementCommand(le_conn) => match le_conn - .specialize() - { - LeConnectionManagementCommandChild::LeCreateConnection(lcc) => { - self.process_le_create_connection( - lcc.get_peer_address(), - lcc.get_initiator_filter_policy(), - packet, - ); - } - LeConnectionManagementCommandChild::LeExtendedCreateConnection(lecc) => { - self.process_le_create_connection( - lecc.get_peer_address(), - lecc.get_initiator_filter_policy(), - packet, - ); - } - LeConnectionManagementCommandChild::LeAddDeviceToFilterAcceptList(laac) => { - self.process_add_accept_list(laac.get_address(), packet); - } - LeConnectionManagementCommandChild::LeRemoveDeviceFromFilterAcceptList( - lrac, - ) => { - self.process_remove_accept_list(lrac.get_address(), packet); - } - LeConnectionManagementCommandChild::LeClearFilterAcceptList(_lcac) => { - self.process_clear_accept_list(packet); - } - LeConnectionManagementCommandChild::LeReadRemoteFeatures(lrrf) => { - self.process_remote_feat_cmd( - PendingRemoteFeature::Le, - &lrrf.get_connection_handle(), - packet, - ); - } - // End LeConnectionManagementCommand.specialize() - _ => {} - }, - AclCommandChild::Disconnect(dc_conn) => { - self.process_disconnect_cmd( - dc_conn.get_reason(), - dc_conn.get_connection_handle(), - packet, - ); - } - - // End AclCommand.specialize() - _ => (), - }, + CommandChild::CreateConnection(cc) => { + self.process_classic_connection(cc.get_bd_addr(), packet); + } + CommandChild::AcceptConnectionRequest(ac) => { + self.process_classic_connection(ac.get_bd_addr(), packet); + } + CommandChild::ReadRemoteSupportedFeatures(rrsf) => { + self.process_remote_feat_cmd( + PendingRemoteFeature::Supported, + &rrsf.get_connection_handle(), + packet, + ); + } + CommandChild::ReadRemoteExtendedFeatures(rref) => { + self.process_remote_feat_cmd( + PendingRemoteFeature::Extended, + &rref.get_connection_handle(), + packet, + ); + } + CommandChild::SetupSynchronousConnection(ssc) => { + let address = self.convert_sco_handle_to_address(ssc.get_connection_handle()); + self.process_sync_connection(address, packet); + } + CommandChild::EnhancedSetupSynchronousConnection(esc) => { + let address = self.convert_sco_handle_to_address(esc.get_connection_handle()); + self.process_sync_connection(address, packet); + } + CommandChild::AcceptSynchronousConnection(asc) => { + self.process_sync_connection(asc.get_bd_addr(), packet); + } + CommandChild::EnhancedAcceptSynchronousConnection(easc) => { + self.process_sync_connection(easc.get_bd_addr(), packet); + } + CommandChild::LeCreateConnection(lcc) => { + self.process_le_create_connection( + lcc.get_peer_address(), + lcc.get_initiator_filter_policy(), + packet, + ); + } + CommandChild::LeExtendedCreateConnection(lecc) => { + self.process_le_create_connection( + lecc.get_peer_address(), + lecc.get_initiator_filter_policy(), + packet, + ); + } + CommandChild::LeAddDeviceToFilterAcceptList(laac) => { + self.process_add_accept_list(laac.get_address(), packet); + } + CommandChild::LeRemoveDeviceFromFilterAcceptList(lrac) => { + self.process_remove_accept_list(lrac.get_address(), packet); + } + CommandChild::LeClearFilterAcceptList(_lcac) => { + self.process_clear_accept_list(packet); + } + CommandChild::LeReadRemoteFeatures(lrrf) => { + self.process_remote_feat_cmd( + PendingRemoteFeature::Le, + &lrrf.get_connection_handle(), + packet, + ); + } + CommandChild::Disconnect(dc_conn) => { + self.process_disconnect_cmd( + dc_conn.get_reason(), + dc_conn.get_connection_handle(), + packet, + ); + } CommandChild::Reset(_) => { self.process_reset(); } @@ -754,6 +729,7 @@ impl Rule for OddDisconnectionsRule { EventChild::NumberOfCompletedPackets(nocp) => { self.process_nocp(&nocp, packet); } + EventChild::AuthenticatedPayloadTimeoutExpired(apte) => { self.process_apte(&apte, packet); } @@ -1008,44 +984,26 @@ impl Rule for LinkKeyMismatchRule { }, PacketChild::HciCommand(cmd) => match cmd.specialize() { - CommandChild::AclCommand(cmd) => match cmd.specialize() { - // Have an arm for Disconnect since sometimes we don't receive disconnect - // event when powering off. However, no need to actually match the reason - // since we just clean the handle in both cases. - AclCommandChild::Disconnect(cmd) => { - self.process_handle_auth( - ErrorCode::Success, - cmd.get_connection_handle(), - &packet, - ); - self.handles.remove(&cmd.get_connection_handle()); - } - - // CommandChild::AclCommand(cmd).specialize() - _ => {} - }, - - CommandChild::SecurityCommand(cmd) => match cmd.specialize() { - SecurityCommandChild::LinkKeyRequestReply(cmd) => { - self.process_reply_link_key(cmd.get_bd_addr(), true); - } - SecurityCommandChild::LinkKeyRequestNegativeReply(cmd) => { - self.process_reply_link_key(cmd.get_bd_addr(), false); - } - - // CommandChild::SecurityCommand(cmd).specialize() - _ => {} - }, - - CommandChild::LeSecurityCommand(cmd) => match cmd.specialize() { - LeSecurityCommandChild::LeStartEncryption(cmd) => { - self.pending_le_encrypt.insert(cmd.get_connection_handle()); - } - - // CommandChild::LeSecurityCommand(cmd).specialize() - _ => {} - }, - + // Have an arm for Disconnect since sometimes we don't receive disconnect + // event when powering off. However, no need to actually match the reason + // since we just clean the handle in both cases. + CommandChild::Disconnect(cmd) => { + self.process_handle_auth( + ErrorCode::Success, + cmd.get_connection_handle(), + &packet, + ); + self.handles.remove(&cmd.get_connection_handle()); + } + CommandChild::LinkKeyRequestReply(cmd) => { + self.process_reply_link_key(cmd.get_bd_addr(), true); + } + CommandChild::LinkKeyRequestNegativeReply(cmd) => { + self.process_reply_link_key(cmd.get_bd_addr(), false); + } + CommandChild::LeStartEncryption(cmd) => { + self.pending_le_encrypt.insert(cmd.get_connection_handle()); + } CommandChild::Reset(_) => { self.process_reset(); } diff --git a/floss/hcidoc/src/groups/informational.rs b/floss/hcidoc/src/groups/informational.rs index e224f481b2..dbaa6c8ae3 100644 --- a/floss/hcidoc/src/groups/informational.rs +++ b/floss/hcidoc/src/groups/informational.rs @@ -10,8 +10,8 @@ use std::io::Write; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{get_acl_content, AclContent, Packet, PacketChild}; use hcidoc_packets::hci::{ - AclCommandChild, Address, CommandChild, ConnectionManagementCommandChild, DisconnectReason, - ErrorCode, EventChild, GapData, GapDataType, LeMetaEventChild, + Address, CommandChild, DisconnectReason, ErrorCode, EventChild, GapData, GapDataType, + LeMetaEventChild, }; use hcidoc_packets::l2cap::{ConnectionResponseResult, ControlChild}; @@ -23,18 +23,27 @@ type Cid = u16; const INVALID_TS: NaiveDateTime = NaiveDateTime::MAX; -fn print_start_end_timestamps(start: NaiveDateTime, end: NaiveDateTime) -> String { - fn print_time(ts: NaiveDateTime) -> String { +fn print_timestamps_and_initiator( + start: NaiveDateTime, + start_initiator: InitiatorType, + end: NaiveDateTime, + end_initiator: InitiatorType, +) -> String { + fn print_time_initiator(ts: NaiveDateTime, initiator: InitiatorType) -> String { if ts == INVALID_TS { return "N/A".to_owned(); } - return format!("{}", ts.time()); + return format!("{} ({})", ts.time(), initiator); } if start == end && start != INVALID_TS { - return format!("{} - Failed", start.time()); + return format!("{} ({}) - Failed", start.time(), start_initiator); } - return format!("{} to {}", print_time(start), print_time(end)); + return format!( + "{} to {}", + print_time_initiator(start, start_initiator), + print_time_initiator(end, end_initiator) + ); } #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] @@ -74,7 +83,7 @@ impl AddressType { } } -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] enum InitiatorType { Unknown, Host, @@ -84,9 +93,9 @@ enum InitiatorType { impl fmt::Display for InitiatorType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let str = match self { - InitiatorType::Unknown => "Unknown initiator", - InitiatorType::Host => "Host initiated", - InitiatorType::Peer => "Peer initiated", + InitiatorType::Unknown => "by ??", + InitiatorType::Host => "by host", + InitiatorType::Peer => "by peer", }; write!(f, "{}", str) } @@ -100,8 +109,8 @@ enum AclState { Connected, } -impl Into<InitiatorType> for AclState { - fn into(self) -> InitiatorType { +impl AclState { + fn get_connection_initiator(&self) -> InitiatorType { match self { AclState::Initiating => InitiatorType::Host, AclState::Accepting => InitiatorType::Peer, @@ -145,15 +154,20 @@ impl DeviceInformation { fn report_connection_start(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) { let mut acl = AclInformation::new(handle); - let initiator = self.acl_state.into(); + let initiator = self.acl_state.get_connection_initiator(); acl.report_start(initiator, ts); self.acls.push(acl); self.acl_state = AclState::Connected; } - fn report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) { + fn report_connection_end( + &mut self, + handle: ConnectionHandle, + initiator: InitiatorType, + ts: NaiveDateTime, + ) { let acl = self.get_or_allocate_connection(&handle); - acl.report_end(ts); + acl.report_end(initiator, ts); self.acl_state = AclState::None; } @@ -195,7 +209,8 @@ struct AclInformation { start_time: NaiveDateTime, end_time: NaiveDateTime, handle: ConnectionHandle, - initiator: InitiatorType, + start_initiator: InitiatorType, + end_initiator: InitiatorType, active_profiles: HashMap<ProfileId, ProfileInformation>, inactive_profiles: Vec<ProfileInformation>, host_cids: HashMap<Cid, CidState>, @@ -208,7 +223,8 @@ impl AclInformation { start_time: INVALID_TS, end_time: INVALID_TS, handle: handle, - initiator: InitiatorType::Unknown, + start_initiator: InitiatorType::Unknown, + end_initiator: InitiatorType::Unknown, active_profiles: HashMap::new(), inactive_profiles: vec![], host_cids: HashMap::new(), @@ -217,16 +233,17 @@ impl AclInformation { } fn report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime) { - self.initiator = initiator; + self.start_initiator = initiator; self.start_time = ts; } - fn report_end(&mut self, ts: NaiveDateTime) { + fn report_end(&mut self, initiator: InitiatorType, ts: NaiveDateTime) { // disconnect the active profiles for (_, mut profile) in self.active_profiles.drain() { - profile.report_end(ts); + profile.report_end(initiator, ts); self.inactive_profiles.push(profile); } + self.end_initiator = initiator; self.end_time = ts; } @@ -237,7 +254,7 @@ impl AclInformation { initiator: InitiatorType, ts: NaiveDateTime, ) { - let mut profile = ProfileInformation::new(profile_type); + let mut profile = ProfileInformation::new(profile_type, profile_id); profile.report_start(initiator, ts); let old_profile = self.active_profiles.insert(profile_id, profile); if let Some(profile) = old_profile { @@ -249,13 +266,14 @@ impl AclInformation { &mut self, profile_type: ProfileType, profile_id: ProfileId, + initiator: InitiatorType, ts: NaiveDateTime, ) { let mut profile = self .active_profiles .remove(&profile_id) - .unwrap_or(ProfileInformation::new(profile_type)); - profile.report_end(ts); + .unwrap_or(ProfileInformation::new(profile_type, profile_id)); + profile.report_end(initiator, ts); self.inactive_profiles.push(profile); } @@ -278,11 +296,12 @@ impl AclInformation { fn report_l2cap_conn_rsp( &mut self, status: ConnectionResponseResult, - host_cid: Cid, - peer_cid: Cid, + cid_info: CidInformation, initiator: InitiatorType, ts: NaiveDateTime, ) { + let host_cid = cid_info.host_cid; + let peer_cid = cid_info.peer_cid; let cid_state_option = match initiator { InitiatorType::Host => self.host_cids.get(&host_cid), InitiatorType::Peer => self.peer_cids.get(&peer_cid), @@ -299,7 +318,7 @@ impl AclInformation { if let Some(psm) = psm_option { let profile_option = ProfileType::from_psm(psm); - let profile_id = ProfileId::L2capCid(host_cid); + let profile_id = ProfileId::L2capCid(cid_info); if status == ConnectionResponseResult::Success { self.host_cids.insert(host_cid, CidState::Connected(peer_cid, psm)); self.peer_cids.insert(peer_cid, CidState::Connected(host_cid, psm)); @@ -310,7 +329,7 @@ impl AclInformation { // On failure, report start and end on the same time. if let Some(profile) = profile_option { self.report_profile_start(profile, profile_id, initiator, ts); - self.report_profile_end(profile, profile_id, ts); + self.report_profile_end(profile, profile_id, initiator, ts); } } } // TODO: debug on the else case. @@ -319,11 +338,11 @@ impl AclInformation { // L2cap disconnected so report profile connection closed if we were tracking it. fn report_l2cap_disconn_rsp( &mut self, - host_cid: Cid, - peer_cid: Cid, - _initiator: InitiatorType, + cid_info: CidInformation, + initiator: InitiatorType, ts: NaiveDateTime, ) { + let host_cid = cid_info.host_cid; let host_cid_state_option = self.host_cids.remove(&host_cid); let host_psm = match host_cid_state_option { Some(cid_state) => match cid_state { @@ -334,6 +353,7 @@ impl AclInformation { None => None, }; + let peer_cid = cid_info.peer_cid; let peer_cid_state_option = self.peer_cids.remove(&peer_cid); let peer_psm = match peer_cid_state_option { Some(cid_state) => match cid_state { @@ -357,8 +377,8 @@ impl AclInformation { let profile_option = ProfileType::from_psm(psm); if let Some(profile) = profile_option { - let profile_id = ProfileId::L2capCid(host_cid); - self.report_profile_end(profile, profile_id, ts) + let profile_id = ProfileId::L2capCid(cid_info); + self.report_profile_end(profile, profile_id, initiator, ts) } } } @@ -367,10 +387,14 @@ impl fmt::Display for AclInformation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let _ = writeln!( f, - " Handle: {handle}, {initiator}, {timestamp_info}", + " Handle: {handle}, {timestamp_initiator_info}", handle = self.handle, - initiator = self.initiator, - timestamp_info = print_start_end_timestamps(self.start_time, self.end_time) + timestamp_initiator_info = print_timestamps_and_initiator( + self.start_time, + self.start_initiator, + self.end_time, + self.end_initiator + ), ); for profile in self.inactive_profiles.iter() { @@ -430,37 +454,61 @@ impl ProfileType { } } +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +struct CidInformation { + host_cid: Cid, + peer_cid: Cid, +} + // Use to distinguish between the same profiles within one ACL connection. // Later we can add RFCOMM's DLCI, for example. +// This is used as the key of the map of active profiles in AclInformation. #[derive(Clone, Copy, Eq, Hash, PartialEq)] enum ProfileId { OnePerConnection(ProfileType), - L2capCid(Cid), + L2capCid(CidInformation), +} + +impl fmt::Display for ProfileId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = match self { + ProfileId::OnePerConnection(_) => "".to_string(), + ProfileId::L2capCid(cid_info) => { + format!("(CID: host={}, peer={})", cid_info.host_cid, cid_info.peer_cid) + } + }; + write!(f, "{}", str) + } } struct ProfileInformation { start_time: NaiveDateTime, end_time: NaiveDateTime, profile_type: ProfileType, - initiator: InitiatorType, + start_initiator: InitiatorType, + end_initiator: InitiatorType, + profile_id: ProfileId, } impl ProfileInformation { - pub fn new(profile_type: ProfileType) -> Self { + pub fn new(profile_type: ProfileType, profile_id: ProfileId) -> Self { ProfileInformation { start_time: INVALID_TS, end_time: INVALID_TS, profile_type: profile_type, - initiator: InitiatorType::Unknown, + start_initiator: InitiatorType::Unknown, + end_initiator: InitiatorType::Unknown, + profile_id: profile_id, } } fn report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime) { - self.initiator = initiator; + self.start_initiator = initiator; self.start_time = ts; } - fn report_end(&mut self, ts: NaiveDateTime) { + fn report_end(&mut self, initiator: InitiatorType, ts: NaiveDateTime) { + self.end_initiator = initiator; self.end_time = ts; } } @@ -469,10 +517,15 @@ impl fmt::Display for ProfileInformation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!( f, - " {profile}, {initiator}, {timestamp_info}", + " {profile}, {timestamp_initiator_info} {profile_id}", profile = self.profile_type, - initiator = self.initiator, - timestamp_info = print_start_end_timestamps(self.start_time, self.end_time) + timestamp_initiator_info = print_timestamps_and_initiator( + self.start_time, + self.start_initiator, + self.end_time, + self.end_initiator + ), + profile_id = self.profile_id, ) } } @@ -484,9 +537,13 @@ struct InformationalRule { sco_handles: HashMap<ConnectionHandle, ConnectionHandle>, /// unknownConnections store connections which is initiated before btsnoop starts. unknown_connections: HashMap<ConnectionHandle, AclInformation>, - /// When powering off, the controller might or might not reply disconnection request. Therefore - /// make this a special case. - pending_disconnect_due_to_host_power_off: HashSet<ConnectionHandle>, + /// Store the pending disconnection so we can retrieve who initiates it upon report. + /// This needs its own map instead of reusing the AclState, because that requires us to have the + /// address of the peer device, but on disconnection we are given only the handle - the address + /// might be unknown, or clash in case of a SCO connection. + /// Also, when powering off, the controller might or might not reply the disconnection request. + /// Therefore also store this information so we can correctly handle both scenario. + pending_disconnections: HashMap<ConnectionHandle, bool>, // is powering off? } impl InformationalRule { @@ -496,7 +553,7 @@ impl InformationalRule { handles: HashMap::new(), sco_handles: HashMap::new(), unknown_connections: HashMap::new(), - pending_disconnect_due_to_host_power_off: HashSet::new(), + pending_disconnections: HashMap::new(), } } @@ -552,7 +609,7 @@ impl InformationalRule { let device = self.get_or_allocate_device(address); device.report_connection_start(handle, ts); self.handles.insert(handle, *address); - self.pending_disconnect_due_to_host_power_off.remove(&handle); + self.pending_disconnections.remove(&handle); } fn report_sco_connection_start( @@ -589,13 +646,21 @@ impl InformationalRule { } fn report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) { + let initiator = match self.pending_disconnections.contains_key(&handle) { + true => InitiatorType::Host, + false => InitiatorType::Peer, + }; + // This might be a SCO disconnection event, so check that first if self.sco_handles.contains_key(&handle) { let acl_handle = self.sco_handles[&handle]; let conn = self.get_or_allocate_connection(&acl_handle); + // in case of HFP failure, the initiator here would be set to peer, which is incorrect, + // but when printing we detect by the timestamp that it was a failure anyway. conn.report_profile_end( ProfileType::Hfp, ProfileId::OnePerConnection(ProfileType::Hfp), + initiator, ts, ); return; @@ -604,8 +669,8 @@ impl InformationalRule { // Not recognized as SCO, assume it's an ACL handle. if let Some(address) = self.handles.get(&handle) { // This device is known - let device = self.devices.get_mut(address).unwrap(); - device.report_connection_end(handle, ts); + let device: &mut DeviceInformation = self.devices.get_mut(address).unwrap(); + device.report_connection_end(handle, initiator, ts); self.handles.remove(&handle); // remove the associated SCO handle, if any @@ -613,7 +678,7 @@ impl InformationalRule { } else { // Unknown device. let conn = self.get_or_allocate_unknown_connection(&handle); - conn.report_end(ts); + conn.report_end(initiator, ts); } } @@ -624,7 +689,7 @@ impl InformationalRule { self.report_connection_end(handle, ts); } self.sco_handles.clear(); - self.pending_disconnect_due_to_host_power_off.clear(); + self.pending_disconnections.clear(); } fn process_gap_data(&mut self, address: &Address, data: &GapData) { @@ -641,18 +706,20 @@ impl InformationalRule { fn process_raw_gap_data(&mut self, address: &Address, data: &[u8]) { let mut offset = 0; while offset < data.len() { - let chunk_size = usize::from(data[offset]); - let chunk_end = offset + chunk_size + 1; - - // Prevent out-of-bounds index - if chunk_end > data.len() { - return; + match GapData::parse(&data[offset..]) { + Ok(gap_data) => { + self.process_gap_data(&address, &gap_data); + // advance data len + 2 (size = 1, type = 1) + offset += gap_data.data.len() + 2; + } + Err(err) => { + eprintln!("[{}] GAP data is not parsed correctly: {}", address, err); + break; + } } - match GapData::parse(&data[offset..chunk_end]) { - Ok(gap_data) => self.process_gap_data(&address, &gap_data), - Err(_err) => {} + if offset >= data.len() { + break; } - offset = chunk_end; } } @@ -681,7 +748,8 @@ impl InformationalRule { return; } let conn = self.get_or_allocate_connection(&handle); - conn.report_l2cap_conn_rsp(status, host_cid, peer_cid, initiator, ts); + let cid_info = CidInformation { host_cid, peer_cid }; + conn.report_l2cap_conn_rsp(status, cid_info, initiator, ts); } fn report_l2cap_disconn_rsp( @@ -693,7 +761,8 @@ impl InformationalRule { ts: NaiveDateTime, ) { let conn = self.get_or_allocate_connection(&handle); - conn.report_l2cap_disconn_rsp(host_cid, peer_cid, initiator, ts); + let cid_info = CidInformation { host_cid, peer_cid }; + conn.report_l2cap_disconn_rsp(cid_info, initiator, ts); } } @@ -729,18 +798,18 @@ impl Rule for InformationalRule { EventChild::DisconnectionComplete(ev) => { // If disconnected because host is powering off, the event has been processed. // We can't just query the reason here because it's different across vendors. - if !self - .pending_disconnect_due_to_host_power_off - .remove(&ev.get_connection_handle()) - { - self.report_connection_end(ev.get_connection_handle(), packet.ts); + let handle = ev.get_connection_handle(); + if !self.pending_disconnections.get(&handle).unwrap_or(&false) { + self.report_connection_end(handle, packet.ts); } + self.pending_disconnections.remove(&handle); } EventChild::ExtendedInquiryResult(ev) => { - for data in ev.get_extended_inquiry_response() { - self.process_gap_data(&ev.get_address(), data); - } + self.process_raw_gap_data( + &ev.get_address(), + ev.get_extended_inquiry_response(), + ); self.report_address_type(&ev.get_address(), AddressType::BREDR); } @@ -785,16 +854,14 @@ impl Rule for InformationalRule { self.report_address_type(&ev.get_peer_address(), AddressType::LE); } - // Use the Raw version because somehow LeAdvertisingReport doesn't work - LeMetaEventChild::LeAdvertisingReportRaw(ev) => { + LeMetaEventChild::LeAdvertisingReport(ev) => { for resp in ev.get_responses() { self.process_raw_gap_data(&resp.address, &resp.advertising_data); self.report_address_type(&resp.address, AddressType::LE); } } - // Use the Raw version because somehow LeExtendedAdvertisingReport doesn't work - LeMetaEventChild::LeExtendedAdvertisingReportRaw(ev) => { + LeMetaEventChild::LeExtendedAdvertisingReport(ev) => { for resp in ev.get_responses() { self.process_raw_gap_data(&resp.address, &resp.advertising_data); self.report_address_type(&resp.address, AddressType::LE); @@ -813,37 +880,24 @@ impl Rule for InformationalRule { CommandChild::Reset(_cmd) => { self.report_reset(packet.ts); } - - CommandChild::AclCommand(cmd) => match cmd.specialize() { - AclCommandChild::ConnectionManagementCommand(cmd) => match cmd.specialize() { - ConnectionManagementCommandChild::CreateConnection(cmd) => { - self.report_acl_state(&cmd.get_bd_addr(), AclState::Initiating); - self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); - } - - ConnectionManagementCommandChild::AcceptConnectionRequest(cmd) => { - self.report_acl_state(&cmd.get_bd_addr(), AclState::Accepting); - self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); - } - - // AclCommandChild::ConnectionManagementCommand(cmd).specialize() - _ => {} - }, - - AclCommandChild::Disconnect(cmd) => { - // If reason is power off, the host might not wait for connection complete event - if cmd.get_reason() - == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff - { - self.pending_disconnect_due_to_host_power_off - .insert(cmd.get_connection_handle()); - self.report_connection_end(cmd.get_connection_handle(), packet.ts); - } + CommandChild::CreateConnection(cmd) => { + self.report_acl_state(&cmd.get_bd_addr(), AclState::Initiating); + self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); + } + CommandChild::AcceptConnectionRequest(cmd) => { + self.report_acl_state(&cmd.get_bd_addr(), AclState::Accepting); + self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); + } + CommandChild::Disconnect(cmd) => { + // If reason is power off, the host might not wait for connection complete event + let is_power_off = cmd.get_reason() + == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff; + let handle = cmd.get_connection_handle(); + self.pending_disconnections.insert(handle, is_power_off); + if is_power_off { + self.report_connection_end(handle, packet.ts); } - - // CommandChild::AclCommand(cmd).specialize() - _ => {} - }, + } // PacketChild::HciCommand(cmd).specialize() _ => {} diff --git a/framework/Android.bp b/framework/Android.bp index 9fa8d9a160..2eca8df89b 100644 --- a/framework/Android.bp +++ b/framework/Android.bp @@ -10,6 +10,7 @@ filegroup { "java/**/*.java", ], path: "java", + visibility: ["//packages/modules/Bluetooth/framework/tests/unit"], } // defaults shared between `framework-bluetooth` & `framework-bluetooth-pre-jarjar` @@ -49,6 +50,7 @@ java_library { sdk_version: "module_current", libs: ["framework-annotations-lib"], installable: false, + visibility: ["//packages/modules/Bluetooth:__subpackages__"], } // post-jarjar version of framework-bluetooth @@ -85,12 +87,14 @@ java_sdk_library { permitted_packages: [ "android.bluetooth", - "com.android.bluetooth.flags", "com.android.bluetooth.jarjar", ], plugins: [ "error_prone_android_framework", ], + aconfig_declarations: [ + "bluetooth_aconfig_flags", + ], lint: { error_checks: [ "Autofill", @@ -146,7 +150,7 @@ java_defaults { // if sdk_version="" this gets automatically included, but here we need to add manually. "framework-res", ], - defaults_visibility: ["//visibility:public"], + defaults_visibility: ["//packages/modules/Bluetooth:__subpackages__"], } filegroup { diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index f7e87588ba..7aa89155b1 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -191,7 +191,7 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int disconnect(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true) public boolean fetchUuidsWithSdp(int); - method @FlaggedApi("com.android.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getActiveAudioDevicePolicy(); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getActiveAudioDevicePolicy(); method @NonNull public String getAnonymizedAddress(); method @IntRange(from=0xffffff9c, to=100) @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getBatteryLevel(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionHandle(int); @@ -210,7 +210,7 @@ package android.bluetooth { method public void prepareToEnterProcess(@NonNull android.content.AttributionSource); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int requestAudioPolicyAsSink(@NonNull android.bluetooth.BluetoothSinkAudioPolicy); - method @FlaggedApi("com.android.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setActiveAudioDevicePolicy(int); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setActiveAudioDevicePolicy(int); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setLowLatencyAudioAllowed(boolean); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMessageAccessPermission(int); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMetadata(int, @NonNull byte[]); @@ -229,9 +229,9 @@ package android.bluetooth { field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PAIRING_CANCEL = "android.bluetooth.device.action.PAIRING_CANCEL"; field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED"; field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_SWITCH_BUFFER_SIZE = "android.bluetooth.device.action.SWITCH_BUFFER_SIZE"; - field @FlaggedApi("com.android.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection") public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION = 1; // 0x1 - field @FlaggedApi("com.android.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection") public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION = 2; // 0x2 - field @FlaggedApi("com.android.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection") public static final int ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT = 0; // 0x0 + field public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION = 1; // 0x1 + field public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION = 2; // 0x2 + field public static final int ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT = 0; // 0x0 field public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100; // 0xffffff9c field public static final int BATTERY_LEVEL_UNKNOWN = -1; // 0xffffffff field public static final int CONNECTION_ACCESS_NO = 2; // 0x2 @@ -479,11 +479,11 @@ package android.bluetooth { field public static final int AUDIO_LOCATION_FRONT_RIGHT = 2; // 0x2 field public static final int AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER = 128; // 0x80 field public static final int AUDIO_LOCATION_FRONT_RIGHT_WIDE = 33554432; // 0x2000000 - field @Deprecated @FlaggedApi("com.android.bluetooth.flags.leaudio_mono_location_errata") public static final int AUDIO_LOCATION_INVALID = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.bluetooth.flags.leaudio_mono_location_errata_api") public static final int AUDIO_LOCATION_INVALID = 0; // 0x0 field public static final int AUDIO_LOCATION_LEFT_SURROUND = 67108864; // 0x4000000 field public static final int AUDIO_LOCATION_LOW_FREQ_EFFECTS_ONE = 8; // 0x8 field public static final int AUDIO_LOCATION_LOW_FREQ_EFFECTS_TWO = 512; // 0x200 - field @FlaggedApi("com.android.bluetooth.flags.leaudio_mono_location_errata") public static final int AUDIO_LOCATION_MONO = 0; // 0x0 + field @FlaggedApi("com.android.bluetooth.flags.leaudio_mono_location_errata_api") public static final int AUDIO_LOCATION_MONO = 0; // 0x0 field public static final int AUDIO_LOCATION_RIGHT_SURROUND = 134217728; // 0x8000000 field public static final int AUDIO_LOCATION_SIDE_LEFT = 1024; // 0x400 field public static final int AUDIO_LOCATION_SIDE_RIGHT = 2048; // 0x800 @@ -496,7 +496,7 @@ package android.bluetooth { field public static final int AUDIO_LOCATION_TOP_FRONT_RIGHT = 8192; // 0x2000 field public static final int AUDIO_LOCATION_TOP_SIDE_LEFT = 262144; // 0x40000 field public static final int AUDIO_LOCATION_TOP_SIDE_RIGHT = 524288; // 0x80000 - field @FlaggedApi("com.android.bluetooth.flags.leaudio_mono_location_errata") public static final int AUDIO_LOCATION_UNKNOWN = -2147483648; // 0x80000000 + field @FlaggedApi("com.android.bluetooth.flags.leaudio_mono_location_errata_api") public static final int AUDIO_LOCATION_UNKNOWN = -2147483648; // 0x80000000 field public static final String EXTRA_LE_AUDIO_GROUP_ID = "android.bluetooth.extra.LE_AUDIO_GROUP_ID"; field public static final int GROUP_STREAM_STATUS_IDLE = 0; // 0x0 field public static final int GROUP_STREAM_STATUS_STREAMING = 1; // 0x1 @@ -1166,8 +1166,8 @@ package android.bluetooth { method @NonNull public byte[] getDeviceAddressWithType(); method @Nullable public byte[] getDeviceName(); method @Nullable public byte[] getLeAppearance(); - method @NonNull public int getLeDeviceRole(); - method @NonNull public int getLeFlags(); + method public int getLeDeviceRole(); + method public int getLeFlags(); method @Nullable public byte[] getLeTemporaryKey(); method @NonNull public byte[] getRandomizerHash(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -1382,9 +1382,9 @@ package android.bluetooth.le { public static interface DistanceMeasurementSession.Callback { method public void onResult(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.le.DistanceMeasurementResult); - method public void onStartFail(@NonNull int); + method public void onStartFail(int); method public void onStarted(@NonNull android.bluetooth.le.DistanceMeasurementSession); - method public void onStopped(@NonNull android.bluetooth.le.DistanceMeasurementSession, @NonNull int); + method public void onStopped(@NonNull android.bluetooth.le.DistanceMeasurementSession, int); } @Deprecated public final class ResultStorageDescriptor implements android.os.Parcelable { diff --git a/framework/jarjar-rules.txt b/framework/jarjar-rules.txt index 172bdd439e..cff2b1aa31 100644 --- a/framework/jarjar-rules.txt +++ b/framework/jarjar-rules.txt @@ -10,3 +10,4 @@ rule android.hardware.radio.V1_0.** com.android.bluetooth.jarjar.@0 rule com.google.android.mms.** com.android.bluetooth.jarjar.@0 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 diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ce8b74f74f..f345bb5502 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1484,21 +1484,36 @@ public final class BluetoothAdapter { throw e.rethrowAsRuntimeException(); } } + @RequiresNoPermission + @Override + public boolean shouldBypassCache(IBluetooth serviceQuery) { + return false; + } }; - private static final IpcDataCache.QueryHandler<IBluetoothManager, Integer> - sBluetoothGetSystemStateQuery = - new IpcDataCache.QueryHandler<>() { - @RequiresNoPermission - @Override - public @InternalAdapterState Integer apply(IBluetoothManager serviceQuery) { - try { - return serviceQuery.getState(); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - }; + private static final IpcDataCache.QueryHandler<Void, Integer> sBluetoothGetSystemStateQuery = + new IpcDataCache.QueryHandler<>() { + @RequiresNoPermission + @Override + public @InternalAdapterState Integer apply(Void query) { + try { + IBluetoothManager service = + IBluetoothManager.Stub.asInterface( + BluetoothFrameworkInitializer.getBluetoothServiceManager() + .getBluetoothManagerServiceRegisterer() + .get()); + return service.getState(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @RequiresNoPermission + @Override + public boolean shouldBypassCache(Void query) { + return false; + } + }; private static final String GET_STATE_API = "BluetoothAdapter_getState"; @@ -1508,9 +1523,9 @@ public final class BluetoothAdapter { private static final IpcDataCache<IBluetooth, Integer> sBluetoothGetStateCache = new BluetoothCache<>(GET_STATE_API, sBluetoothGetStateQuery); - private static final IpcDataCache<IBluetoothManager, Integer> sBluetoothGetSystemStateCache = + private static final IpcDataCache<Void, Integer> sBluetoothGetSystemStateCache = new IpcDataCache<>( - 8, + 1, IBluetoothManager.IPC_CACHE_MODULE_SYSTEM, GET_SYSTEM_STATE_API, GET_SYSTEM_STATE_API, @@ -1536,14 +1551,7 @@ public final class BluetoothAdapter { /** Fetch the current bluetooth state. If the service is down, return OFF. */ private @InternalAdapterState int getStateInternal() { if (Flags.getStateFromSystemServer()) { - try { - return sBluetoothGetSystemStateCache.query(mManagerService); - } catch (RuntimeException runtime) { - if (runtime.getCause() instanceof RemoteException e) { - throw e.rethrowFromSystemServer(); - } - throw runtime; - } + return sBluetoothGetSystemStateCache.query(null); } mServiceLock.readLock().lock(); try { @@ -2405,6 +2413,11 @@ public final class BluetoothAdapter { throw e.rethrowAsRuntimeException(); } } + @RequiresNoPermission + @Override + public boolean shouldBypassCache(IBluetooth serviceQuery) { + return false; + } }; private static final String FILTERING_API = "BluetoothAdapter_isOffloadedFilteringSupported"; @@ -2948,6 +2961,11 @@ public final class BluetoothAdapter { throw e.rethrowAsRuntimeException(); } } + @RequiresNoPermission + @Override + public boolean shouldBypassCache(IBluetooth serviceQuery) { + return false; + } }; private static final String GET_CONNECTION_API = "BluetoothAdapter_getConnectionState"; @@ -3017,6 +3035,12 @@ public final class BluetoothAdapter { throw e.rethrowAsRuntimeException(); } } + @RequiresNoPermission + @Override + public boolean shouldBypassCache( + Pair<IBluetooth, Pair<AttributionSource, Integer>> pairQuery) { + return false; + } }; private static final String PROFILE_API = "BluetoothAdapter_getProfileConnectionState"; diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java index 4da94af0d8..9bd547d33a 100644 --- a/framework/java/android/bluetooth/BluetoothDevice.java +++ b/framework/java/android/bluetooth/BluetoothDevice.java @@ -1361,7 +1361,6 @@ public final class BluetoothDevice implements Parcelable, Attributable { * * @hide */ - @FlaggedApi(Flags.FLAG_METADATA_API_INACTIVE_AUDIO_DEVICE_UPON_CONNECTION) @SystemApi public static final int ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT = 0; @@ -1372,7 +1371,6 @@ public final class BluetoothDevice implements Parcelable, Attributable { * * @hide */ - @FlaggedApi(Flags.FLAG_METADATA_API_INACTIVE_AUDIO_DEVICE_UPON_CONNECTION) @SystemApi public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION = 1; @@ -1383,7 +1381,6 @@ public final class BluetoothDevice implements Parcelable, Attributable { * * @hide */ - @FlaggedApi(Flags.FLAG_METADATA_API_INACTIVE_AUDIO_DEVICE_UPON_CONNECTION) @SystemApi public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION = 2; @@ -3460,7 +3457,6 @@ public final class BluetoothDevice implements Parcelable, Attributable { * @throws IllegalArgumentException if this BluetoothDevice object has an invalid address * @hide */ - @FlaggedApi(Flags.FLAG_METADATA_API_INACTIVE_AUDIO_DEVICE_UPON_CONNECTION) @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) @@ -3492,7 +3488,6 @@ public final class BluetoothDevice implements Parcelable, Attributable { * @return active audio device policy of the device * @hide */ - @FlaggedApi(Flags.FLAG_METADATA_API_INACTIVE_AUDIO_DEVICE_UPON_CONNECTION) @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) diff --git a/framework/java/android/bluetooth/BluetoothLeAudio.java b/framework/java/android/bluetooth/BluetoothLeAudio.java index c11efe1683..6bc4a73de9 100644 --- a/framework/java/android/bluetooth/BluetoothLeAudio.java +++ b/framework/java/android/bluetooth/BluetoothLeAudio.java @@ -367,7 +367,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { * with a meaning MONO. * @hide */ - @FlaggedApi(Flags.FLAG_LEAUDIO_MONO_LOCATION_ERRATA) + @FlaggedApi(Flags.FLAG_LEAUDIO_MONO_LOCATION_ERRATA_API) @Deprecated @SystemApi public static final int AUDIO_LOCATION_INVALID = 0; @@ -377,7 +377,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { * * @hide */ - @FlaggedApi(Flags.FLAG_LEAUDIO_MONO_LOCATION_ERRATA) + @FlaggedApi(Flags.FLAG_LEAUDIO_MONO_LOCATION_ERRATA_API) @SystemApi public static final int AUDIO_LOCATION_MONO = 0; @@ -386,7 +386,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { * * @hide */ - @FlaggedApi(Flags.FLAG_LEAUDIO_MONO_LOCATION_ERRATA) + @FlaggedApi(Flags.FLAG_LEAUDIO_MONO_LOCATION_ERRATA_API) @SystemApi public static final int AUDIO_LOCATION_UNKNOWN = 0x01 << 31; @@ -1186,6 +1186,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + @SuppressWarnings("FlaggedApi") // Due to deprecated AUDIO_LOCATION_INVALID public @AudioLocation int getAudioLocation(@NonNull BluetoothDevice device) { if (VDBG) log("getAudioLocation()"); final IBluetoothLeAudio service = getService(); @@ -1200,7 +1201,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { } } - if (Flags.leaudioMonoLocationErrata() + if (Flags.leaudioMonoLocationErrataApi() && CompatChanges.isChangeEnabled(LEAUDIO_MONO_LOCATION_ERRATA)) { return AUDIO_LOCATION_UNKNOWN; } diff --git a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java index b802943b49..28b4e779ee 100644 --- a/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java +++ b/framework/java/android/bluetooth/BluetoothLeBroadcastAssistant.java @@ -316,6 +316,8 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au * Callback invoked when a new Broadcast Source is found together with the {@link * BluetoothLeBroadcastMetadata}. * + * <p>Broadcast is found when it is available for user to synchronize with it. + * * @param source {@link BluetoothLeBroadcastMetadata} representing a Broadcast Source * @hide */ @@ -443,8 +445,7 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au /** * Callback invoked when the Broadcast Source is lost together with source broadcast id. * - * <p>This callback is to notify source lost due to periodic advertising sync lost. Callback - * client can know that the source notified by {@link + * <p>Callback client can know that the source notified by {@link * Callback#onSourceFound(BluetoothLeBroadcastMetadata)} before is not available any more * after this callback. * diff --git a/framework/java/android/bluetooth/OobData.java b/framework/java/android/bluetooth/OobData.java index a90516d616..e6c5f945d8 100644 --- a/framework/java/android/bluetooth/OobData.java +++ b/framework/java/android/bluetooth/OobData.java @@ -750,7 +750,6 @@ public final class OobData implements Parcelable { * 55 of LMP Feature Mask Definitions. <b>0x05- 0x07 Reserved</b> * @hide */ - @NonNull @SystemApi @LeFlag public int getLeFlags() { @@ -766,7 +765,6 @@ public final class OobData implements Parcelable { * Preferred 0x04 - 0xFF Reserved * @hide */ - @NonNull @SystemApi public @LeRole int getLeDeviceRole() { return mLeDeviceRole; @@ -849,7 +847,7 @@ public final class OobData implements Parcelable { } // For Parcelable - public static final @android.annotation.NonNull Parcelable.Creator<OobData> CREATOR = + public static final @NonNull Parcelable.Creator<OobData> CREATOR = new Parcelable.Creator<OobData>() { public OobData createFromParcel(Parcel in) { return new OobData(in); diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementSession.java b/framework/java/android/bluetooth/le/DistanceMeasurementSession.java index d91fbade2c..a36887ba9b 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementSession.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementSession.java @@ -177,7 +177,7 @@ public final class DistanceMeasurementSession { * @hide */ @SystemApi - void onStartFail(@NonNull @Reason int reason); + void onStartFail(@Reason int reason); /** * Invoked when a distance measurement session stopped. @@ -186,7 +186,7 @@ public final class DistanceMeasurementSession { * @hide */ @SystemApi - void onStopped(@NonNull DistanceMeasurementSession session, @NonNull @Reason int reason); + void onStopped(@NonNull DistanceMeasurementSession session, @Reason int reason); /** * Invoked when get distance measurement result. diff --git a/framework/tests/bumble/Android.bp b/framework/tests/bumble/Android.bp index a97112171c..6c516acf11 100644 --- a/framework/tests/bumble/Android.bp +++ b/framework/tests/bumble/Android.bp @@ -54,7 +54,7 @@ java_test_host { "tradefed", ], - data: [ + device_common_data: [ ":BumbleBluetoothTestsApp", "bumble_config.json", ], @@ -80,9 +80,11 @@ java_test_host { ], data: [ - ":BumbleBluetoothTestsApp", "bumble_config.json", ], + device_common_data: [ + ":BumbleBluetoothTestsApp", + ], data_native_bins: [ "bumble_pandora_server", ], diff --git a/framework/tests/metrics/host/Android.bp b/framework/tests/metrics/host/Android.bp index f90e35a29d..4bb72818a1 100644 --- a/framework/tests/metrics/host/Android.bp +++ b/framework/tests/metrics/host/Android.bp @@ -16,7 +16,7 @@ java_test_host { "tradefed", ], - data: [ + device_common_data: [ ":BluetoothMetricsTestApp", ], diff --git a/framework/tests/unit/Android.bp b/framework/tests/unit/Android.bp index 96025ab7fb..39b3c29861 100644 --- a/framework/tests/unit/Android.bp +++ b/framework/tests/unit/Android.bp @@ -5,8 +5,7 @@ package { android_test { name: "FrameworkBluetoothTests", - defaults: ["framework-bluetooth-tests-defaults"], - + sdk_version: "module_current", min_sdk_version: "Tiramisu", target_sdk_version: "current", @@ -19,11 +18,14 @@ android_test { libs: [ "android.test.base.stubs", "android.test.runner.stubs", + "framework-annotations-lib", + "framework-bluetooth.impl", ], static_libs: [ "androidx.test.ext.truth", "androidx.test.rules", "flag-junit", + "framework-bluetooth-pre-jarjar", "frameworks-base-testutils", "junit", "mockito-target", diff --git a/framework/tests/unit/src/android/bluetooth/CallbackWrapperTest.java b/framework/tests/unit/src/android/bluetooth/CallbackWrapperTest.java index a55fb033bc..0721ead366 100644 --- a/framework/tests/unit/src/android/bluetooth/CallbackWrapperTest.java +++ b/framework/tests/unit/src/android/bluetooth/CallbackWrapperTest.java @@ -22,8 +22,6 @@ import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import android.os.Handler; -import android.os.HandlerExecutor; import android.os.test.TestLooper; import androidx.test.filters.SmallTest; @@ -72,7 +70,7 @@ public class CallbackWrapperTest { @Before public void setUp() { mLooper = new TestLooper(); - mExecutor = new HandlerExecutor(new Handler(mLooper.getLooper())); + mExecutor = mLooper.getNewExecutor(); mCallbackExecutorMap = new HashMap(); mCallbackWrapper = new CallbackWrapper(mRegisterConsumer, mUnregisterConsumer, mCallbackExecutorMap); diff --git a/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java b/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java index ac228c6c9d..a690e510f5 100644 --- a/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java +++ b/framework/tests/unit/src/android/bluetooth/le/ScanRecordTest.java @@ -22,7 +22,6 @@ import android.os.ParcelUuid; import android.platform.test.flag.junit.SetFlagsRule; import com.android.bluetooth.flags.Flags; -import com.android.internal.util.HexDump; import com.android.modules.utils.BytesMatcher; import org.junit.Rule; @@ -70,11 +69,10 @@ public class ScanRecordTest { final List<String> found = new ArrayList<>(); final Predicate<byte[]> matcher = (v) -> { - found.add(HexDump.toHexString(v)); + found.add(toHexString(v)); return false; }; - ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_URL)) - .matchesAnyField(matcher); + ScanRecord.parseFromBytes(hexStringToByteArray(RECORD_URL)).matchesAnyField(matcher); assertThat(found) .isEqualTo( @@ -112,11 +110,10 @@ public class ScanRecordTest { final List<String> found = new ArrayList<>(); final Predicate<byte[]> matcher = (v) -> { - found.add(HexDump.toHexString(v)); + found.add(toHexString(v)); return false; }; - ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_IBEACON)) - .matchesAnyField(matcher); + ScanRecord.parseFromBytes(hexStringToByteArray(RECORD_IBEACON)).matchesAnyField(matcher); assertThat(found) .isEqualTo( @@ -265,16 +262,49 @@ public class ScanRecordTest { } private static void assertMatchesAnyField(String record, BytesMatcher matcher) { - assertThat( - ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) - .matchesAnyField(matcher)) + assertThat(ScanRecord.parseFromBytes(hexStringToByteArray(record)).matchesAnyField(matcher)) .isTrue(); } private static void assertNotMatchesAnyField(String record, BytesMatcher matcher) { - assertThat( - ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record)) - .matchesAnyField(matcher)) + assertThat(ScanRecord.parseFromBytes(hexStringToByteArray(record)).matchesAnyField(matcher)) .isFalse(); } + + private static final char[] HEX_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + private static String toHexString(byte[] array) { + char[] buf = new char[array.length * 2]; + + int bufIndex = 0; + for (int i = 0; i < array.length; i++) { + byte b = array[i]; + buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; + buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; + } + + return new String(buf); + } + + private static int toByte(char c) { + if (c >= '0' && c <= '9') return (c - '0'); + if (c >= 'A' && c <= 'F') return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') return (c - 'a' + 10); + + throw new RuntimeException("Invalid hex char '" + c + "'"); + } + + private static byte[] hexStringToByteArray(String hexString) { + int length = hexString.length(); + byte[] buffer = new byte[length / 2]; + + for (int i = 0; i < length; i += 2) { + buffer[i / 2] = + (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1))); + } + + return buffer; + } } diff --git a/pandora/interfaces/pandora_experimental/vcp.proto b/pandora/interfaces/pandora_experimental/vcp.proto new file mode 100644 index 0000000000..42641c8545 --- /dev/null +++ b/pandora/interfaces/pandora_experimental/vcp.proto @@ -0,0 +1,47 @@ +// 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. + +syntax = "proto3"; + +package pandora.vcp; + +import "pandora/host.proto"; +option java_outer_classname = "VcpProto"; +import "google/protobuf/empty.proto"; + +service VCP { + // set absolute volume on remote device + rpc SetDeviceVolume(SetDeviceVolumeRequest) returns (google.protobuf.Empty); + // set volume offset on remote device + rpc SetVolumeOffset(SetVolumeOffsetRequest) returns (google.protobuf.Empty); + // Wait for device to be connected. + rpc WaitConnect(WaitConnectRequest) returns (google.protobuf.Empty); +} + +// Request of the `SetDeviceVolume` method +message SetDeviceVolumeRequest{ + // Connection crafted by grpc server + Connection connection = 1; + // Volume value to be set + int32 volume = 2; +} + +// Request of the `SetVolumeOffset` method +message SetVolumeOffsetRequest{ + // Connection crafted by grpc server + Connection connection = 1; + // Volume offset value to be set + int32 offset = 2; +} + +message WaitConnectRequest { + Connection connection = 1; +} diff --git a/pandora/interfaces/python/Android.bp b/pandora/interfaces/python/Android.bp index d295f2cfd3..c866c4a138 100644 --- a/pandora/interfaces/python/Android.bp +++ b/pandora/interfaces/python/Android.bp @@ -95,6 +95,10 @@ genrule { "pandora_experimental/rfcomm_grpc_aio.py", "pandora_experimental/rfcomm_pb2.py", "pandora_experimental/rfcomm_pb2.pyi", + "pandora_experimental/vcp_grpc.py", + "pandora_experimental/vcp_grpc_aio.py", + "pandora_experimental/vcp_pb2.py", + "pandora_experimental/vcp_pb2.pyi", ], } @@ -129,6 +133,7 @@ filegroup { ":pandora_experimental-python-gen-src{pandora_experimental/pbap_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/py.typed}", ":pandora_experimental-python-gen-src{pandora_experimental/rfcomm_pb2.pyi}", + ":pandora_experimental-python-gen-src{pandora_experimental/vcp_pb2.pyi}", ], } diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java index b59ab9de45..8bd003641d 100644 --- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java +++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java @@ -142,7 +142,7 @@ class BluetoothManagerService { // Delay for the addProxy function in msec private static final int ADD_PROXY_DELAY_MS = 100 * HW_MULTIPLIER; // Delay for retrying enable and disable in msec - private static final int ENABLE_DISABLE_DELAY_MS = 300 * HW_MULTIPLIER; + @VisibleForTesting static final int ENABLE_DISABLE_DELAY_MS = 300 * HW_MULTIPLIER; @VisibleForTesting static final int MESSAGE_ENABLE = 1; @VisibleForTesting static final int MESSAGE_DISABLE = 2; @@ -157,10 +157,8 @@ class BluetoothManagerService { @VisibleForTesting static final int MESSAGE_GET_NAME_AND_ADDRESS = 200; @VisibleForTesting static final int MESSAGE_USER_SWITCHED = 300; @VisibleForTesting static final int MESSAGE_USER_UNLOCKED = 301; - @VisibleForTesting static final int MESSAGE_RESTORE_USER_SETTING = 500; - - private static final int RESTORE_SETTING_TO_ON = 1; - private static final int RESTORE_SETTING_TO_OFF = 0; + @VisibleForTesting static final int MESSAGE_RESTORE_USER_SETTING_OFF = 501; + @VisibleForTesting static final int MESSAGE_RESTORE_USER_SETTING_ON = 502; private static final int MAX_ERROR_RESTART_RETRIES = 6; private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10; @@ -184,7 +182,7 @@ class BluetoothManagerService { private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks = new RemoteCallbackList<>(); private final BluetoothServiceBinder mBinder; - private final BluetoothHandler mHandler; + @VisibleForTesting final BluetoothHandler mHandler; private final ContentResolver mContentResolver; private final Context mContext; private final Looper mLooper; @@ -401,39 +399,30 @@ class BluetoothManagerService { private static final Object ON_SWITCH_USER_TOKEN = new Object(); Unit onAirplaneModeChanged(boolean isAirplaneModeOn) { - mHandler.postDelayed( - () -> - delayModeChangedIfNeeded( - ON_AIRPLANE_MODE_CHANGED_TOKEN, - () -> handleAirplaneModeChanged(isAirplaneModeOn), - "onAirplaneModeChanged"), + delayModeChangedIfNeeded( ON_AIRPLANE_MODE_CHANGED_TOKEN, - 0); + () -> handleAirplaneModeChanged(isAirplaneModeOn), + "onAirplaneModeChanged"); return Unit.INSTANCE; } // TODO(b/289584302): Update to private once use_new_satellite_mode is enabled Unit onSatelliteModeChanged(boolean isSatelliteModeOn) { - mHandler.postDelayed( - () -> - delayModeChangedIfNeeded( - ON_SATELLITE_MODE_CHANGED_TOKEN, - () -> handleSatelliteModeChanged(isSatelliteModeOn), - "onSatelliteModeChanged"), + delayModeChangedIfNeeded( ON_SATELLITE_MODE_CHANGED_TOKEN, - 0); + () -> handleSatelliteModeChanged(isSatelliteModeOn), + "onSatelliteModeChanged"); return Unit.INSTANCE; } + // Call is coming from the systemServer main thread and need to be post to avoid race void onSwitchUser(UserHandle userHandle) { - mHandler.postDelayed( + mHandler.post( () -> delayModeChangedIfNeeded( ON_SWITCH_USER_TOKEN, () -> handleSwitchUser(userHandle), - "onSwitchUser"), - ON_SWITCH_USER_TOKEN, - 0); + "onSwitchUser")); } private void forceToOffFromModeChange(int currentState, int reason) { @@ -460,29 +449,31 @@ class BluetoothManagerService { } private void handleAirplaneModeChanged(boolean isAirplaneModeOn) { - synchronized (this) { - if (isBluetoothPersistedStateOn()) { - if (isAirplaneModeOn) { - setBluetoothPersistedState(BLUETOOTH_ON_AIRPLANE); - } else { - setBluetoothPersistedState(BLUETOOTH_ON_BLUETOOTH); - } + boolean isPersistStateOn = isBluetoothPersistedStateOn(); + if (isPersistStateOn) { + if (isAirplaneModeOn) { + setBluetoothPersistedState(BLUETOOTH_ON_AIRPLANE); + } else { + setBluetoothPersistedState(BLUETOOTH_ON_BLUETOOTH); } + } - int currentState = mState.get(); + int currentState = mState.get(); - Log.d( - TAG, - ("handleAirplaneModeChanged(" + isAirplaneModeOn + "):") - + (" currentState=" + nameForState(currentState))); - - if (isAirplaneModeOn) { - forceToOffFromModeChange(currentState, ENABLE_DISABLE_REASON_AIRPLANE_MODE); - } else if (mEnableExternal) { - sendEnableMsg(mQuietEnableExternal, ENABLE_DISABLE_REASON_AIRPLANE_MODE); - } else if (currentState != STATE_ON) { - autoOnSetupTimer(); - } + Log.d( + TAG, + ("handleAirplaneModeChanged(" + isAirplaneModeOn + "):") + + (" mEnableExternal=" + mEnableExternal) + + (" isPersistStateOn=" + isPersistStateOn) + + (" currentState=" + nameForState(currentState))); + + if (isAirplaneModeOn) { + forceToOffFromModeChange(currentState, ENABLE_DISABLE_REASON_AIRPLANE_MODE); + } else if (mEnableExternal && currentState != STATE_ON && isPersistStateOn) { + // isPersistStateOn is checked to prevent race with RESTORE_USER_SETTING + sendEnableMsg(mQuietEnableExternal, ENABLE_DISABLE_REASON_AIRPLANE_MODE); + } else if (currentState != STATE_ON) { + autoOnSetupTimer(); } } @@ -557,17 +548,15 @@ class BluetoothManagerService { + (" prevValue=" + prevValue) + (" newValue=" + newValue)); - if ((newValue != null) - && (prevValue != null) - && !prevValue.equals(newValue)) { - mHandler.obtainMessage( - MESSAGE_RESTORE_USER_SETTING, - newValue.equals("0") - ? RESTORE_SETTING_TO_OFF - : RESTORE_SETTING_TO_ON, - 0) - .sendToTarget(); + if ((newValue == null) + || (prevValue == null) + || prevValue.equals(newValue)) { + return; } + mHandler.sendEmptyMessage( + newValue.equals("0") + ? MESSAGE_RESTORE_USER_SETTING_OFF + : MESSAGE_RESTORE_USER_SETTING_ON); } } else if (action.equals(Intent.ACTION_SHUTDOWN)) { Log.i(TAG, "Device is shutting down."); @@ -1539,24 +1528,26 @@ class BluetoothManagerService { } break; - case MESSAGE_RESTORE_USER_SETTING: - if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) { - Log.d(TAG, "MESSAGE_RESTORE_USER_SETTING: set Bluetooth state to disabled"); - setBluetoothPersistedState(BLUETOOTH_OFF); - mEnableExternal = false; - sendDisableMsg(ENABLE_DISABLE_REASON_RESTORE_USER_SETTING); - } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) { - Log.d(TAG, "MESSAGE_RESTORE_USER_SETTING: set Bluetooth state to enabled"); - mQuietEnableExternal = false; - mEnableExternal = true; - sendEnableMsg(false, ENABLE_DISABLE_REASON_RESTORE_USER_SETTING); - } else { - Log.w( - TAG, - "MESSAGE_RESTORE_USER_SETTING: Unhandled." - + (" mEnable=" + mEnable) - + (" msg.arg1=" + msg.arg1)); + case MESSAGE_RESTORE_USER_SETTING_OFF: + if (!mEnable) { + Log.w(TAG, "RESTORE_USER_SETTING_OFF: Unhandled: already disabled"); + break; + } + Log.d(TAG, "RESTORE_USER_SETTING_OFF: set Bluetooth state to disabled"); + setBluetoothPersistedState(BLUETOOTH_OFF); + mEnableExternal = false; + sendDisableMsg(ENABLE_DISABLE_REASON_RESTORE_USER_SETTING); + break; + + case MESSAGE_RESTORE_USER_SETTING_ON: + if (mEnable) { + Log.w(TAG, "RESTORE_USER_SETTING_ON: Unhandled: already enabled"); + break; } + Log.d(TAG, "RESTORE_USER_SETTING_ON: set Bluetooth state to enabled"); + mQuietEnableExternal = false; + mEnableExternal = true; + sendEnableMsg(false, ENABLE_DISABLE_REASON_RESTORE_USER_SETTING); break; case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: @@ -1618,14 +1609,10 @@ class BluetoothManagerService { bluetoothStateChangeHandler(prevState, newState); // handle error state transition case from TURNING_ON to OFF // unbind and rebind bluetooth service and enable bluetooth - if ((prevState == STATE_BLE_TURNING_ON) - && (newState == STATE_OFF) - && mEnable) { + if ((prevState == STATE_BLE_TURNING_ON) && (newState == STATE_OFF) && mEnable) { recoverBluetoothServiceFromError(false); } - if ((prevState == STATE_TURNING_ON) - && (newState == STATE_BLE_ON) - && mEnable) { + if ((prevState == STATE_TURNING_ON) && (newState == STATE_BLE_ON) && mEnable) { recoverBluetoothServiceFromError(true); } // If we tried to enable BT while BT was in the process of shutting down, diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java index 4be1786c36..8c4a2c9fa8 100644 --- a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java +++ b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java @@ -19,6 +19,7 @@ package com.android.server.bluetooth; import static android.bluetooth.BluetoothAdapter.STATE_BLE_ON; import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_ON; +import static android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_CONNECTED; @@ -26,7 +27,9 @@ import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUET import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_STATE_CHANGE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_DISABLE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_ENABLE; +import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_HANDLE_DISABLE_DELAYED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_RESTART_BLUETOOTH_SERVICE; +import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_RESTORE_USER_SETTING_OFF; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_TIMEOUT_BIND; import static com.google.common.truth.Truth.assertThat; @@ -101,6 +104,7 @@ public class BluetoothManagerServiceTest { } private static final int STATE_BLE_TURNING_ON = 14; // can't find the symbol because hidden api + private static final int STATE_BLE_TURNING_OFF = 16; // can't find the symbol because hidden api BluetoothManagerService mManagerService; @@ -185,6 +189,7 @@ public class BluetoothManagerServiceTest { doReturn(mAdapterBinder).when(mBluetoothServerProxy).createAdapterBinder(any()); doReturn(mAdapterService).when(mAdapterBinder).getAdapterBinder(); + doReturn(mBinder).when(mAdapterService).asBinder(); doReturn(mock(Intent.class)) .when(mContext) @@ -238,6 +243,17 @@ public class BluetoothManagerServiceTest { }); } + private void discardMessage(int... what) { + IntStream.of(what) + .forEach( + w -> { + Message msg = mLooper.nextMessage(); + assertThat(msg).isNotNull(); + assertThat(msg.what).isEqualTo(w); + // Drop the message + }); + } + @Test public void onUserRestrictionsChanged_disallowBluetooth_onlySendDisableMessageOnSystemUser() throws InterruptedException { @@ -358,6 +374,22 @@ public class BluetoothManagerServiceTest { return btCallback; } + private void transition_onToBleOn(IBluetoothCallback btCallback) throws Exception { + verify(mAdapterBinder).onToBleOn(any()); + + btCallback.onBluetoothStateChange(STATE_TURNING_OFF, STATE_BLE_ON); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + } + + private void transition_onToOff(IBluetoothCallback btCallback) throws Exception { + transition_onToBleOn(btCallback); + verify(mAdapterBinder).bleOnToOff(any()); + + // When all the profile are started, adapterService consider it is ON + btCallback.onBluetoothStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + } + @Test public void enable_whileTurningToBleOn_shouldEnable() throws Exception { mManagerService.enableBle("enable_whileTurningToBleOn_shouldEnable", mBinder); @@ -450,9 +482,47 @@ public class BluetoothManagerServiceTest { assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); mLooper.moveTimeForward(120_000); - Message msg = mLooper.nextMessage(); - assertThat(msg).isNotNull(); - assertThat(msg.what).isEqualTo(MESSAGE_RESTART_BLUETOOTH_SERVICE); - // Discard the msg without executing it + discardMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); + } + + @Test + public void disableAirplane_whenNothing_startBluetooth() throws Exception { + doReturn(BluetoothManagerService.BLUETOOTH_ON_BLUETOOTH) + .when(mBluetoothServerProxy) + .getBluetoothPersistedState(any(), anyInt()); + mManagerService.enable("disableAirplane_whenNothing_startBluetooth"); + discardMessage(MESSAGE_ENABLE); + + mManagerService.onAirplaneModeChanged(false); + discardMessage(MESSAGE_ENABLE); + } + + @Test + public void disableAirplane_whenFactoryReset_doesNotStartBluetooth() throws Exception { + doAnswer( + invocation -> { + IBinder.DeathRecipient recipient = invocation.getArgument(0); + recipient.binderDied(); + return null; + }) + .when(mBinder) + .linkToDeath(any(), anyInt()); + + mManagerService.enable("test_offToOn"); + syncHandler(MESSAGE_ENABLE); + IBluetoothCallback btCallback = transition_offToOn(); + assertThat(mManagerService.getState()).isEqualTo(STATE_ON); + + mManagerService.mHandler.sendEmptyMessage(MESSAGE_RESTORE_USER_SETTING_OFF); + syncHandler(MESSAGE_RESTORE_USER_SETTING_OFF); + syncHandler(MESSAGE_DISABLE); + mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); + syncHandler(MESSAGE_HANDLE_DISABLE_DELAYED); + mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); + syncHandler(MESSAGE_HANDLE_DISABLE_DELAYED); + transition_onToOff(btCallback); + + mManagerService.onAirplaneModeChanged(false); + assertThat(mLooper.nextMessage()).isNull(); // Must not create a MESSAGE_ENABLE } } diff --git a/system/Android.bp b/system/Android.bp index b788868c0e..b79fa12489 100644 --- a/system/Android.bp +++ b/system/Android.bp @@ -307,11 +307,13 @@ cc_genrule { ":BlueberryFacadeAndCertGeneratedStub_py", ":bluetooth_cert_test_host_deps-zip", ":bluetooth_cert_test_sources-zip", - ":bluetooth_cert_test_target_deps-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 && " + diff --git a/system/audio_hal_interface/a2dp_encoding.h b/system/audio_hal_interface/a2dp_encoding.h index d23d023e35..d1de4138b2 100644 --- a/system/audio_hal_interface/a2dp_encoding.h +++ b/system/audio_hal_interface/a2dp_encoding.h @@ -46,6 +46,8 @@ enum class BluetoothAudioStatus { /// Implements callbacks for the BT Audio HAL to start, suspend and configure /// the audio stream. Completion of the requested operation is indicated /// by the methods ack_stream_started, ack_stream_suspended. +/// +/// The callbacks are always invoked from one of the binder threads. class BluetoothAudioPort { public: virtual ~BluetoothAudioPort() {} diff --git a/system/audio_hal_interface/a2dp_encoding_host.cc b/system/audio_hal_interface/a2dp_encoding_host.cc index e9bb187339..92f4361b78 100644 --- a/system/audio_hal_interface/a2dp_encoding_host.cc +++ b/system/audio_hal_interface/a2dp_encoding_host.cc @@ -27,7 +27,6 @@ #include "btif/include/btif_a2dp_source.h" #include "btif/include/btif_av.h" #include "btif/include/btif_hf.h" -#include "os/log.h" #include "stack/include/avdt_api.h" #include "types/raw_address.h" #include "udrv/include/uipc.h" diff --git a/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.h b/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.h index 32ef7923d8..f470d5e06a 100644 --- a/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.h +++ b/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.h @@ -22,7 +22,6 @@ #include "a2dp_sbc_constants.h" #include "common/message_loop_thread.h" #include "hardware/bt_av.h" -#include "os/log.h" #include "osi/include/properties.h" #include "types/raw_address.h" diff --git a/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc b/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc index 9f4c86b2cf..074929290b 100644 --- a/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc +++ b/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc @@ -33,7 +33,6 @@ #include "a2dp_vendor_ldac_constants.h" #include "a2dp_vendor_opus_constants.h" #include "client_interface_aidl.h" -#include "os/log.h" namespace bluetooth::audio::aidl::a2dp { diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.cc b/system/audio_hal_interface/aidl/client_interface_aidl.cc index 87e29cdab9..e8b143fb5d 100644 --- a/system/audio_hal_interface/aidl/client_interface_aidl.cc +++ b/system/audio_hal_interface/aidl/client_interface_aidl.cc @@ -135,8 +135,6 @@ void BluetoothAudioClientInterface::FetchAudioProvider() { if (provider_ != nullptr) { log::warn("refetch"); } - // Prevent other access to the AIDL if currently fetching new service - std::lock_guard<std::mutex> guard(internal_mutex_); // Retry if audioserver restarts in the middle of fetching. // When audioserver restarts, IBluetoothAudioProviderFactory service is also // re-registered, so we need to re-fetch the service. diff --git a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc index 64f4d3d6e4..b6a761889b 100644 --- a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc +++ b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc @@ -22,7 +22,6 @@ #include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" #include "client_interface_aidl.h" -#include "os/log.h" #include "osi/include/properties.h" namespace fmt { diff --git a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc index 8e3d8bfa03..7ba08289d0 100644 --- a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc +++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc @@ -28,7 +28,6 @@ #include <vector> #include "hal_version_manager.h" -#include "os/log.h" namespace bluetooth { namespace audio { diff --git a/system/audio_hal_interface/hal_version_manager.cc b/system/audio_hal_interface/hal_version_manager.cc index 19c48c58da..2068b766e9 100644 --- a/system/audio_hal_interface/hal_version_manager.cc +++ b/system/audio_hal_interface/hal_version_manager.cc @@ -24,7 +24,6 @@ #include <memory> #include "aidl/audio_aidl_interfaces.h" -#include "os/log.h" namespace bluetooth { namespace audio { diff --git a/system/audio_hal_interface/hfp_client_interface.cc b/system/audio_hal_interface/hfp_client_interface.cc index 22e6b99373..9ff47a3490 100644 --- a/system/audio_hal_interface/hfp_client_interface.cc +++ b/system/audio_hal_interface/hfp_client_interface.cc @@ -24,7 +24,6 @@ #include "aidl/hfp_client_interface_aidl.h" #include "hal_version_manager.h" #include "hfp_client_interface.h" -#include "os/log.h" #include "osi/include/properties.h" using ::bluetooth::audio::aidl::hfp::HfpDecodingTransport; diff --git a/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc b/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc index 7f32ca7a2a..f80aac6b43 100644 --- a/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc +++ b/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc @@ -22,7 +22,6 @@ #include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" #include "client_interface_hidl.h" -#include "os/log.h" #include "osi/include/properties.h" namespace fmt { diff --git a/system/audio_hal_interface/hidl/le_audio_software_hidl.cc b/system/audio_hal_interface/hidl/le_audio_software_hidl.cc index 94f8b8745b..740c05a0ad 100644 --- a/system/audio_hal_interface/hidl/le_audio_software_hidl.cc +++ b/system/audio_hal_interface/hidl/le_audio_software_hidl.cc @@ -21,8 +21,6 @@ #include <bluetooth/log.h> -#include "os/log.h" - namespace bluetooth { namespace audio { namespace hidl { diff --git a/system/audio_hal_interface/le_audio_software.cc b/system/audio_hal_interface/le_audio_software.cc index 7061f865e6..a984d966ee 100644 --- a/system/audio_hal_interface/le_audio_software.cc +++ b/system/audio_hal_interface/le_audio_software.cc @@ -31,7 +31,6 @@ #include "bta/le_audio/le_audio_types.h" #include "hal_version_manager.h" #include "hidl/le_audio_software_hidl.h" -#include "os/log.h" #include "osi/include/properties.h" namespace bluetooth { diff --git a/system/bta/Android.bp b/system/bta/Android.bp index 235246605f..4ffce6907d 100644 --- a/system/bta/Android.bp +++ b/system/bta/Android.bp @@ -260,6 +260,7 @@ cc_test { ":TestMockStackAvdt", ":TestMockStackAvrc", ":TestMockStackBtm", + ":TestMockStackConnMgr", ":TestMockStackGap", ":TestMockStackGatt", ":TestMockStackHid", @@ -325,7 +326,7 @@ cc_test { "libgmock", "server_configurable_flags", ], - data: [ + device_first_data: [ ":audio_set_configurations_bfbs", ":audio_set_configurations_json", ":audio_set_scenarios_bfbs", @@ -791,7 +792,7 @@ cc_test { "le_audio/le_audio_types.cc", "le_audio/le_audio_utils.cc", ], - data: [ + device_first_data: [ ":audio_set_configurations_bfbs", ":audio_set_configurations_json", ":audio_set_scenarios_bfbs", @@ -900,7 +901,7 @@ cc_test { "test/common/btm_api_mock.cc", "test/common/mock_csis_client.cc", ], - data: [ + device_first_data: [ ":audio_set_configurations_bfbs", ":audio_set_configurations_json", ":audio_set_scenarios_bfbs", @@ -1026,7 +1027,7 @@ cc_test { "libosi", "server_configurable_flags", ], - data: [ + device_first_data: [ ":audio_set_configurations_bfbs", ":audio_set_configurations_json", ":audio_set_scenarios_bfbs", diff --git a/system/bta/ag/bta_ag_at.cc b/system/bta/ag/bta_ag_at.cc index 2a7a24022d..a42017c29b 100644 --- a/system/bta/ag/bta_ag_at.cc +++ b/system/bta/ag/bta_ag_at.cc @@ -34,7 +34,6 @@ #include "bta/ag/bta_ag_int.h" #include "bta/include/utl.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" using namespace bluetooth; diff --git a/system/bta/ag/bta_ag_int.h b/system/bta/ag/bta_ag_int.h index 2173d86d62..21d39365a3 100644 --- a/system/bta/ag/bta_ag_int.h +++ b/system/bta/ag/bta_ag_int.h @@ -34,6 +34,7 @@ #include "bta/include/bta_api.h" #include "bta/sys/bta_sys.h" #include "internal_include/bt_target.h" +#include "os/logging/log_adapter.h" #include "stack/include/bt_hdr.h" #include "stack/include/btm_api_types.h" #include "stack/include/sdp_status.h" diff --git a/system/bta/av/bta_av_act.cc b/system/bta/av/bta_av_act.cc index fdc2cfcb98..a01920504d 100644 --- a/system/bta/av/bta_av_act.cc +++ b/system/bta/av/bta_av_act.cc @@ -321,7 +321,7 @@ static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode, t * Returns the created rc handle * ******************************************************************************/ -uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, uint8_t lidx) { +uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, tAVCT_ROLE role, uint8_t shdl, uint8_t lidx) { if ((!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() && !btif_av_is_sink_enabled() && btif_av_is_source_enabled())) && @@ -330,14 +330,13 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, uint8_t l return BTA_AV_RC_HANDLE_NONE; } - tAVRC_CONN_CB ccb; RawAddress bda = RawAddress::kAny; uint8_t status = BTA_AV_RC_ROLE_ACP; int i; uint8_t rc_handle; - tBTA_AV_RCB* p_rcb; + tBTA_AV_RCB* p_rcb{nullptr}; - if (role == AVCT_INT) { + if (role == AVCT_ROLE_INITIATOR) { // Can't grab a stream control block that doesn't have a valid handle if (!shdl) { log::error("Can't grab stream control block for shdl = {} -> index = {}", shdl, shdl - 1); @@ -357,14 +356,16 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, uint8_t l } } - ccb.ctrl_cback = base::Bind(bta_av_rc_ctrl_cback); - ccb.msg_cback = base::Bind(bta_av_rc_msg_cback); - ccb.company_id = p_bta_av_cfg->company_id; - ccb.conn = role; - /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL - */ - ccb.control = p_cb->features & - (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA | AVRC_CT_PASSIVE); + tAVRC_CONN_CB ccb = { + .ctrl_cback = base::Bind(bta_av_rc_ctrl_cback), + .msg_cback = base::Bind(bta_av_rc_msg_cback), + .company_id = p_bta_av_cfg->company_id, + .conn = role, + // note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL + .control = + static_cast<uint8_t>(p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | + BTA_AV_FEAT_METADATA | AVRC_CT_PASSIVE)), + }; if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS) { DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(bda, IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT); @@ -392,8 +393,8 @@ uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, uint8_t l p_cb->rc_acp_idx = (i + 1); log::verbose("rc_acp_handle:{} idx:{}", p_cb->rc_acp_handle, p_cb->rc_acp_idx); } - log::verbose("create {}, role: {}, shdl:{}, rc_handle:{}, lidx:{}, status:0x{:x}", i, role, shdl, - p_rcb->handle, lidx, p_rcb->status); + log::verbose("create {}, role: {}, shdl:{}, rc_handle:{}, lidx:{}, status:0x{:x}", i, + avct_role_text(role), shdl, p_rcb->handle, lidx, p_rcb->status); return rc_handle; } @@ -539,7 +540,7 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { /* listen to browsing channel when the connection is open, * if peer initiated AVRCP connection and local device supports browsing * channel */ - AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ACP); + AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ROLE_ACCEPTOR); if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0) { /* rc is opened on the RC only ACP channel, but is for a specific @@ -618,7 +619,7 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { (rc_open.peer_tg_features & BTA_AV_FEAT_BROWSE))) { if ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) { log::verbose("opening AVRC Browse channel"); - AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT); + AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ROLE_INITIATOR); } } return; @@ -649,7 +650,7 @@ void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) { if ((p_cb->features & BTA_AV_FEAT_BROWSE) && (rc_open.peer_features & BTA_AV_FEAT_BROWSE) && ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) { log::verbose("opening AVRC Browse channel"); - AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT); + AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ROLE_INITIATOR); } } @@ -1335,7 +1336,7 @@ void bta_av_conn_chg(tBTA_AV_DATA* p_data) { /* if the AVRCP is no longer listening, create the listening channel */ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG) { - bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + bta_av_rc_create(&bta_av_cb, AVCT_ROLE_ACCEPTOR, 0, BTA_AV_NUM_LINKS + 1); } } @@ -1554,7 +1555,7 @@ void bta_av_sig_chg(tBTA_AV_DATA* p_data) { p_lcb->conn_msk = 0; /* clear the connect mask */ /* start listening when the signal channel is open */ if (p_cb->features & BTA_AV_FEAT_RCTG) { - bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx); + bta_av_rc_create(p_cb, AVCT_ROLE_ACCEPTOR, 0, p_lcb->lidx); } /* this entry is not used yet. */ p_cb->conn_lcb |= mask; /* mark it as used */ @@ -2118,7 +2119,8 @@ static void bta_av_rc_disc_done_all(tBTA_AV_DATA* /* p_data */) { ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_ct_features & BTA_AV_FEAT_RCCT))) { p_lcb = bta_av_find_lcb(p_scb->PeerAddress(), BTA_AV_LCB_FIND); if (p_lcb) { - rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (uint8_t)(p_scb->hdi + 1), p_lcb->lidx); + rc_handle = bta_av_rc_create(p_cb, AVCT_ROLE_INITIATOR, (uint8_t)(p_scb->hdi + 1), + p_lcb->lidx); if (rc_handle != BTA_AV_RC_HANDLE_NONE) { p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features; p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features; @@ -2302,7 +2304,8 @@ void bta_av_rc_disc_done(tBTA_AV_DATA* p_data) { ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) { p_lcb = bta_av_find_lcb(p_scb->PeerAddress(), BTA_AV_LCB_FIND); if (p_lcb) { - rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (uint8_t)(p_scb->hdi + 1), p_lcb->lidx); + rc_handle = bta_av_rc_create(p_cb, AVCT_ROLE_INITIATOR, (uint8_t)(p_scb->hdi + 1), + p_lcb->lidx); if (rc_handle < BTA_AV_NUM_RCB) { p_cb->rcb[rc_handle].peer_features = peer_features; p_cb->rcb[rc_handle].cover_art_psm = cover_art_psm; @@ -2484,7 +2487,7 @@ void bta_av_rc_closed(tBTA_AV_DATA* p_data) { bta_av_data.rc_close = rc_close; (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, &bta_av_data); if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG) { - bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + bta_av_rc_create(&bta_av_cb, AVCT_ROLE_ACCEPTOR, 0, BTA_AV_NUM_LINKS + 1); } } diff --git a/system/bta/av/bta_av_api.cc b/system/bta/av/bta_av_api.cc index 2c349e4334..0d3b26a086 100644 --- a/system/bta/av/bta_av_api.cc +++ b/system/bta/av/bta_av_api.cc @@ -32,7 +32,6 @@ #include "btif/include/btif_av.h" #include "internal_include/bt_target.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "stack/include/bt_hdr.h" diff --git a/system/bta/av/bta_av_ci.cc b/system/bta/av/bta_av_ci.cc index 2fa1afb079..7a83c8570a 100644 --- a/system/bta/av/bta_av_ci.cc +++ b/system/bta/av/bta_av_ci.cc @@ -30,7 +30,6 @@ #include <bluetooth/log.h> #include "bta/av/bta_av_int.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/bta/av/bta_av_int.h b/system/bta/av/bta_av_int.h index 94c63226e0..4f9773344e 100644 --- a/system/bta/av/bta_av_int.h +++ b/system/bta/av/bta_av_int.h @@ -37,6 +37,7 @@ #include "macros.h" #include "osi/include/list.h" #include "stack/include/a2dp_constants.h" +#include "stack/include/avct_api.h" #include "stack/include/avdt_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/hci_error_code.h" @@ -526,7 +527,7 @@ public: bool use_rc; /* true if AVRCP is allowed */ bool started; /* true if stream started */ bool use_rtp_header_marker_bit; /* true if the encoded data packets have RTP - * headers, and the Marker bit in the header + * headers, with the Marker bit in the header * is set according to RFC 6416 */ uint8_t co_started; /* non-zero, if stream started from call-out perspective */ bool recfg_sup; /* true if the first attempt to reconfigure the stream was @@ -708,7 +709,7 @@ bool bta_av_chk_start(tBTA_AV_SCB* p_scb); void bta_av_restore_switch(void); void bta_av_conn_cback(uint8_t handle, const RawAddress& bd_addr, uint8_t event, tAVDT_CTRL* p_data, uint8_t scb_index); -uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl, uint8_t lidx); +uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, tAVCT_ROLE role, uint8_t shdl, uint8_t lidx); void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started); bool bta_av_is_scb_opening(tBTA_AV_SCB* p_scb); bool bta_av_is_scb_incoming(tBTA_AV_SCB* p_scb); diff --git a/system/bta/av/bta_av_main.cc b/system/bta/av/bta_av_main.cc index d8573d7f02..a992882a08 100644 --- a/system/bta/av/bta_av_main.cc +++ b/system/bta/av/bta_av_main.cc @@ -649,7 +649,7 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { } /* start listening when A2DP is registered */ if (bta_av_cb.features & BTA_AV_FEAT_RCTG) { - bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + bta_av_rc_create(&bta_av_cb, AVCT_ROLE_ACCEPTOR, 0, BTA_AV_NUM_LINKS + 1); } /* if the AV and AVK are both supported, it cannot support the CT role @@ -658,7 +658,7 @@ static void bta_av_api_register(tBTA_AV_DATA* p_data) { /* if TG is not supported, we need to register to AVCT now */ if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) { bta_ar_reg_avct(); - bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + bta_av_rc_create(&bta_av_cb, AVCT_ROLE_ACCEPTOR, 0, BTA_AV_NUM_LINKS + 1); } if (com::android::bluetooth::flags::avrcp_sdp_records()) { // Add control record for sink profile. diff --git a/system/bta/av/bta_av_ssm.cc b/system/bta/av/bta_av_ssm.cc index 56c03a00cc..37df2021a2 100644 --- a/system/bta/av/bta_av_ssm.cc +++ b/system/bta/av/bta_av_ssm.cc @@ -28,7 +28,6 @@ #include "bta/av/bta_av_int.h" #include "internal_include/bt_target.h" -#include "os/log.h" using namespace bluetooth; diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index 1d1d5c589d..792aa44b6e 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -52,7 +52,7 @@ #include "main/shim/entry.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/include/acl_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" diff --git a/system/bta/dm/bta_dm_pm.cc b/system/bta/dm/bta_dm_pm.cc index dfd93ca2dc..ca3bb38058 100644 --- a/system/bta/dm/bta_dm_pm.cc +++ b/system/bta/dm/bta_dm_pm.cc @@ -39,7 +39,6 @@ #include "hci/controller_interface.h" #include "main/shim/dumpsys.h" #include "main/shim/entry.h" -#include "os/log.h" #include "osi/include/properties.h" #include "stack/include/acl_api.h" #include "stack/include/btm_client_interface.h" diff --git a/system/bta/gatt/bta_gattc_api.cc b/system/bta/gatt/bta_gattc_api.cc index d4dfc500b1..38b3691b4a 100644 --- a/system/bta/gatt/bta_gattc_api.cc +++ b/system/bta/gatt/bta_gattc_api.cc @@ -34,7 +34,6 @@ #include "bta/gatt/bta_gattc_int.h" #include "gd/hci/uuid.h" #include "gd/os/rand.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/main_thread.h" diff --git a/system/bta/gatt/bta_gattc_db_storage.cc b/system/bta/gatt/bta_gattc_db_storage.cc index 6a741e8544..34beb0852c 100644 --- a/system/bta/gatt/bta_gattc_db_storage.cc +++ b/system/bta/gatt/bta_gattc_db_storage.cc @@ -28,7 +28,6 @@ #include "bta/gatt/bta_gattc_int.h" #include "gatt/database.h" -#include "os/log.h" #include "stack/include/gattdefs.h" #include "types/bluetooth/uuid.h" diff --git a/system/bta/gatt/bta_gattc_main.cc b/system/bta/gatt/bta_gattc_main.cc index fc642edfd4..2912879e77 100644 --- a/system/bta/gatt/bta_gattc_main.cc +++ b/system/bta/gatt/bta_gattc_main.cc @@ -28,7 +28,6 @@ #include "bta/gatt/bta_gattc_int.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "stack/include/bt_hdr.h" using base::StringPrintf; diff --git a/system/bta/gatt/bta_gattc_queue.cc b/system/bta/gatt/bta_gattc_queue.cc index 6d2cc8c887..40d99a7fb5 100644 --- a/system/bta/gatt/bta_gattc_queue.cc +++ b/system/bta/gatt/bta_gattc_queue.cc @@ -24,7 +24,6 @@ #include <vector> #include "bta_gatt_queue.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/eatt/eatt.h" diff --git a/system/bta/gatt/bta_gatts_queue.cc b/system/bta/gatt/bta_gatts_queue.cc index 1344f036f0..ef6a73e9d9 100644 --- a/system/bta/gatt/bta_gatts_queue.cc +++ b/system/bta/gatt/bta_gatts_queue.cc @@ -23,7 +23,6 @@ #include <unordered_set> #include "bta_gatt_server_queue.h" -#include "os/log.h" using gatts_operation = BtaGattServerQueue::gatts_operation; using bluetooth::Uuid; diff --git a/system/bta/gmap/gmap_client.cc b/system/bta/gmap/gmap_client.cc index 7cd8d8c054..917070e2ac 100644 --- a/system/bta/gmap/gmap_client.cc +++ b/system/bta/gmap/gmap_client.cc @@ -33,7 +33,6 @@ #include "gap_api.h" #include "gatt_api.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/properties.h" #include "stack/include/bt_types.h" diff --git a/system/bta/gmap/gmap_server.cc b/system/bta/gmap/gmap_server.cc index deb0e9cb3c..6d5ca2cd47 100644 --- a/system/bta/gmap/gmap_server.cc +++ b/system/bta/gmap/gmap_server.cc @@ -38,7 +38,6 @@ #include "gd/os/rand.h" #include "include/hardware/bt_gmap.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "os/logging/log_adapter.h" #include "osi/include/properties.h" #include "stack/include/bt_types.h" diff --git a/system/bta/has/has_client.cc b/system/bta/has/has_client.cc index de671e9dfa..15f69ab76a 100644 --- a/system/bta/has/has_client.cc +++ b/system/bta/has/has_client.cc @@ -39,7 +39,6 @@ #include "gatt_api.h" #include "has_types.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/properties.h" #include "stack/include/bt_types.h" diff --git a/system/bta/has/has_ctp.cc b/system/bta/has/has_ctp.cc index 080298fc9e..c39bef152a 100644 --- a/system/bta/has/has_ctp.cc +++ b/system/bta/has/has_ctp.cc @@ -19,7 +19,7 @@ #include <bluetooth/log.h> -#include "os/log.h" +#include "os/logging/log_adapter.h" #include "stack/include/bt_types.h" using namespace bluetooth; diff --git a/system/bta/hd/bta_hd_api.cc b/system/bta/hd/bta_hd_api.cc index 09c353b7df..3f5d3827a2 100644 --- a/system/bta/hd/bta_hd_api.cc +++ b/system/bta/hd/bta_hd_api.cc @@ -32,7 +32,6 @@ #include <bluetooth/log.h> #include "bta/hd/bta_hd_int.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "stack/include/bt_hdr.h" diff --git a/system/bta/hearing_aid/hearing_aid_audio_source.cc b/system/bta/hearing_aid/hearing_aid_audio_source.cc index 429bb4f0ce..ccc6708079 100644 --- a/system/bta/hearing_aid/hearing_aid_audio_source.cc +++ b/system/bta/hearing_aid/hearing_aid_audio_source.cc @@ -29,7 +29,6 @@ #include "bta/include/bta_hearing_aid_api.h" #include "common/repeating_timer.h" #include "common/time_util.h" -#include "os/log.h" #include "osi/include/wakelock.h" #include "stack/include/main_thread.h" #include "udrv/include/uipc.h" diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc index 9be68cab97..883d0f0955 100644 --- a/system/bta/hf_client/bta_hf_client_at.cc +++ b/system/bta/hf_client/bta_hf_client_at.cc @@ -23,7 +23,6 @@ #include "bta/hf_client/bta_hf_client_int.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "osi/include/properties.h" diff --git a/system/bta/hf_client/bta_hf_client_sdp.cc b/system/bta/hf_client/bta_hf_client_sdp.cc index a9dc87489c..94ebd87917 100644 --- a/system/bta/hf_client/bta_hf_client_sdp.cc +++ b/system/bta/hf_client/bta_hf_client_sdp.cc @@ -33,7 +33,6 @@ #include "bta/include/bta_rfcomm_scn.h" #include "bta/sys/bta_sys.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_types.h" #include "stack/include/bt_uuid16.h" diff --git a/system/bta/hh/bta_hh_api.cc b/system/bta/hh/bta_hh_api.cc index 10ca7f2d65..413eeb9b6d 100644 --- a/system/bta/hh/bta_hh_api.cc +++ b/system/bta/hh/bta_hh_api.cc @@ -30,7 +30,6 @@ #include "bta/hh/bta_hh_int.h" #include "bta/sys/bta_sys.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/main_thread.h" diff --git a/system/bta/hh/bta_hh_main.cc b/system/bta/hh/bta_hh_main.cc index a4dd1444b4..1601663573 100644 --- a/system/bta/hh/bta_hh_main.cc +++ b/system/bta/hh/bta_hh_main.cc @@ -31,7 +31,6 @@ #include "bta/hh/bta_hh_int.h" #include "main/shim/dumpsys.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/bta/hh/bta_hh_utils.cc b/system/bta/hh/bta_hh_utils.cc index c163c1e5ab..b5b86cf94d 100644 --- a/system/bta/hh/bta_hh_utils.cc +++ b/system/bta/hh/bta_hh_utils.cc @@ -26,7 +26,6 @@ #include "btif/include/btif_storage.h" #include "device/include/interop.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/btm_client_interface.h" #include "stack/include/btm_status.h" diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h index 43f5fc1d72..8772fe183c 100644 --- a/system/bta/include/bta_api.h +++ b/system/bta/include/bta_api.h @@ -35,7 +35,6 @@ #include "bta_api_data_types.h" #include "hci/le_rand_callback.h" #include "macros.h" -#include "os/log.h" #include "stack/btm/btm_eir.h" #include "stack/btm/power_mode.h" #include "stack/include/bt_dev_class.h" diff --git a/system/bta/jv/bta_jv_act.cc b/system/bta/jv/bta_jv_act.cc index 852204ed61..cb00b7b6f8 100644 --- a/system/bta/jv/bta_jv_act.cc +++ b/system/bta/jv/bta_jv_act.cc @@ -38,8 +38,6 @@ #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/btm/btm_sec.h" -#include "stack/include/avct_api.h" // AVCT_PSM -#include "stack/include/avdt_api.h" // AVDT_PSM #include "stack/include/bt_hdr.h" #include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" @@ -621,8 +619,8 @@ bool bta_jv_check_psm(uint16_t psm) { } break; - case AVCT_PSM: /* 0x17 */ - case AVDT_PSM: /* 0x19 */ + case BT_PSM_AVCTP: /* 0x17 */ + case BT_PSM_AVDTP: /* 0x19 */ if (!bta_sys_is_register(BTA_ID_AV)) { ret = true; } diff --git a/system/bta/le_audio/audio_hal_client/audio_sink_hal_client.cc b/system/bta/le_audio/audio_hal_client/audio_sink_hal_client.cc index 8f05b7248b..2f86a94e5b 100644 --- a/system/bta/le_audio/audio_hal_client/audio_sink_hal_client.cc +++ b/system/bta/le_audio/audio_hal_client/audio_sink_hal_client.cc @@ -24,7 +24,6 @@ #include "audio_hal_interface/le_audio_software.h" #include "bta/le_audio/codec_manager.h" #include "common/time_util.h" -#include "os/log.h" #include "osi/include/wakelock.h" #include "stack/include/main_thread.h" 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 b721d4546d..bd7c8bea85 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 @@ -30,7 +30,6 @@ #include "common/repeating_timer.h" #include "common/time_util.h" #include "gd/hal/link_clocker.h" -#include "os/log.h" #include "osi/include/wakelock.h" #include "stack/include/main_thread.h" diff --git a/system/bta/le_audio/broadcaster/broadcaster.cc b/system/bta/le_audio/broadcaster/broadcaster.cc index a7b05339b1..251091a8b4 100644 --- a/system/bta/le_audio/broadcaster/broadcaster.cc +++ b/system/bta/le_audio/broadcaster/broadcaster.cc @@ -913,13 +913,16 @@ public: is_iso_running_ = is_active; log::info("is_iso_running: {}", is_iso_running_); if (!is_iso_running_) { - if (queued_start_broadcast_request_) { - auto broadcast_id = *queued_start_broadcast_request_; - queued_start_broadcast_request_ = std::nullopt; + if (!com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { + if (queued_start_broadcast_request_) { + auto broadcast_id = *queued_start_broadcast_request_; + queued_start_broadcast_request_ = std::nullopt; - log::info("Start queued broadcast."); - StartAudioBroadcast(broadcast_id); + log::info("Start queued broadcast."); + StartAudioBroadcast(broadcast_id); + } } + if (queued_create_broadcast_request_) { auto broadcast_msg = std::move(*queued_create_broadcast_request_); queued_create_broadcast_request_ = std::nullopt; diff --git a/system/bta/le_audio/broadcaster/broadcaster_test.cc b/system/bta/le_audio/broadcaster/broadcaster_test.cc index 1145b93a4a..63b708039e 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_test.cc +++ b/system/bta/le_audio/broadcaster/broadcaster_test.cc @@ -533,8 +533,19 @@ TEST_F(BroadcasterTest, CreateAudioBroadcastMultiGroups) { TEST_F(BroadcasterTest, SuspendAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); + LeAudioSourceAudioHalClient::Callbacks* audio_receiver; + EXPECT_CALL(*mock_audio_source_, Start) + .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))) + .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); + + if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { + ASSERT_NE(audio_receiver, nullptr); + audio_receiver->OnAudioResume(); + } else { + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); + } + Mock::VerifyAndClearExpectations(mock_codec_manager_); EXPECT_CALL(mock_broadcaster_callbacks_, @@ -559,7 +570,9 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); + auto broadcast_id = InstantiateBroadcast(); + ASSERT_NE(audio_receiver, nullptr); Mock::VerifyAndClearExpectations(mock_codec_manager_); EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) @@ -575,8 +588,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); - ASSERT_NE(audio_receiver, nullptr); + audio_receiver->OnAudioResume(); // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the @@ -609,6 +621,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { .Times(1); auto broadcast_id = InstantiateBroadcast(media_metadata, default_code, {bluetooth::le_audio::QUALITY_HIGH}); + ASSERT_NE(audio_receiver, nullptr); Mock::VerifyAndClearExpectations(mock_codec_manager_); LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); @@ -626,8 +639,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false)) .Times(0); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); - ASSERT_NE(audio_receiver, nullptr); + audio_receiver->OnAudioResume(); // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the @@ -651,8 +663,18 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { TEST_F(BroadcasterTest, StopAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); + LeAudioSourceAudioHalClient::Callbacks* audio_receiver; + EXPECT_CALL(*mock_audio_source_, Start) + .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))) + .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); + + if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { + ASSERT_NE(audio_receiver, nullptr); + audio_receiver->OnAudioResume(); + } else { + LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); + } // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the @@ -712,7 +734,6 @@ TEST_F(BroadcasterTest, DestroyAudioBroadcast) { LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); EXPECT_CALL(*mock_audio_source_, Start).Times(0); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); EXPECT_CALL(*mock_audio_source_, Stop).Times(0); LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id); @@ -846,8 +867,8 @@ TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA, media_ccid); auto broadcast_id = InstantiateBroadcast(); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); + audio_receiver->OnAudioResume(); auto sm = MockBroadcastStateMachine::GetLastInstance(); std::vector<uint8_t> ccid_list; @@ -1204,6 +1225,7 @@ TEST_F(BroadcasterTest, AudioActiveState) { .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); + ASSERT_NE(audio_receiver, nullptr); auto sm = MockBroadcastStateMachine::GetLastInstance(); pb_announcement = sm->GetPublicBroadcastAnnouncement(); auto created_public_meta = types::LeAudioLtvMap(pb_announcement.metadata).RawPacket(); @@ -1218,9 +1240,6 @@ TEST_F(BroadcasterTest, AudioActiveState) { }); ON_CALL(*sm, GetPublicBroadcastAnnouncement()).WillByDefault(ReturnRef(pb_announcement)); - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); - ASSERT_NE(audio_receiver, nullptr); - // Update to true Audio Active State while audio resumed EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement); audio_receiver->OnAudioResume(); @@ -1278,32 +1297,12 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundFromTheBeginnin auto broadcast_id = InstantiateBroadcast(); EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING)) - .Times(1); + .Times(0); // Timers not started ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); - - // Start Broadcast - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); - // Timers started - ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); - ASSERT_TRUE(big_terminate_timer_->cb != nullptr); - ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); + ASSERT_EQ(0, get_func_call_count("alarm_set_on_mloop")); ASSERT_NE(audio_receiver, nullptr); - - // BIG termination timer execution, state machine go to CONFIGURED state so BIG terminated - EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED)) - .Times(1); - // Imitate execution of BIG termination timer - big_terminate_timer_->cb(big_terminate_timer_->data); - - // Broadcast stop timer execution, state machine go to STOPPED state - EXPECT_CALL(mock_broadcaster_callbacks_, - OnBroadcastStateChanged(broadcast_id, BroadcastState::STOPPED)) - .Times(1); - // Imitate execution of BIG termination timer - broadcast_stop_timer_->cb(broadcast_stop_timer_->data); } TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { @@ -1326,24 +1325,11 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); - // Timers started - ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); - ASSERT_TRUE(big_terminate_timer_->cb != nullptr); - ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); - ASSERT_NE(audio_receiver, nullptr); - - // First onAudioResume when BIG already created, not cause any state change - EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0); audio_receiver->OnAudioResume(); - // Timers cancelled - ASSERT_EQ(2, get_func_call_count("alarm_cancel")); - ASSERT_TRUE(big_terminate_timer_->cb == nullptr); - ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); - ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); + ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); @@ -1357,7 +1343,7 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); - ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop")); + ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); @@ -1396,24 +1382,11 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) { ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast - LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); - // Timers started - ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); - ASSERT_TRUE(big_terminate_timer_->cb != nullptr); - ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); - ASSERT_NE(audio_receiver, nullptr); - - // First onAudioResume when BIG already created, not cause any state change - EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0); audio_receiver->OnAudioResume(); - // Timers cancelled - ASSERT_EQ(2, get_func_call_count("alarm_cancel")); - ASSERT_TRUE(big_terminate_timer_->cb == nullptr); - ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); - ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); + ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); @@ -1427,7 +1400,7 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) { // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); - ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop")); + ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); diff --git a/system/bta/le_audio/broadcaster/mock_state_machine.h b/system/bta/le_audio/broadcaster/mock_state_machine.h index ebafbed398..6b35b11532 100644 --- a/system/bta/le_audio/broadcaster/mock_state_machine.h +++ b/system/bta/le_audio/broadcaster/mock_state_machine.h @@ -30,6 +30,7 @@ public: advertising_sid_ = ++instance_counter_; ON_CALL(*this, Initialize).WillByDefault([this]() { + SetState(State::CONFIGURED); this->cb->OnStateMachineCreateStatus(this->cfg.broadcast_id, result_); return result_; }); diff --git a/system/bta/le_audio/broadcaster/state_machine.cc b/system/bta/le_audio/broadcaster/state_machine.cc index 07c258683a..d81011b655 100644 --- a/system/bta/le_audio/broadcaster/state_machine.cc +++ b/system/bta/le_audio/broadcaster/state_machine.cc @@ -30,7 +30,6 @@ #include "bta/le_audio/le_audio_types.h" #include "common/strings.h" #include "hci/le_advertising_manager.h" -#include "os/log.h" #include "osi/include/properties.h" #include "stack/include/btm_iso_api.h" diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc index e76c7eee2d..01c2856e99 100644 --- a/system/bta/le_audio/client.cc +++ b/system/bta/le_audio/client.cc @@ -365,6 +365,36 @@ public: } } + void StartSuspendTimeout(void) { + StopSuspendTimeout(); + + /* Group should tie in time to get requested status */ + uint64_t timeoutMs = kAudioSuspentKeepIsoAliveTimeoutMs; + timeoutMs = osi_property_get_int32(kAudioSuspentKeepIsoAliveTimeoutMsProp, timeoutMs); + + if (stack_config_get_interface()->get_pts_le_audio_disable_ases_before_stopping()) { + timeoutMs += kAudioDisableTimeoutMs; + } + + log::debug("Stream suspend_timeout_ started: {} ms", static_cast<int>(timeoutMs)); + + alarm_set_on_mloop( + suspend_timeout_, timeoutMs, + [](void* data) { + if (instance) { + instance->GroupStop(PTR_TO_INT(data)); + } + }, + INT_TO_PTR(active_group_id_)); + } + + void StopSuspendTimeout(void) { + if (alarm_is_scheduled(suspend_timeout_)) { + log::debug("Cancel suspend timeout"); + alarm_cancel(suspend_timeout_); + } + } + void AseInitialStateReadRequest(LeAudioDevice* leAudioDevice) { int ases_num = leAudioDevice->ases_.size(); void* notify_flag_ptr = NULL; @@ -1292,9 +1322,7 @@ public: sink_monitor_notified_status_ = std::nullopt; log::info("Group id: {}", active_group_id_); - if (alarm_is_scheduled(suspend_timeout_)) { - alarm_cancel(suspend_timeout_); - } + StopSuspendTimeout(); StopAudio(); ClientAudioInterfaceRelease(); @@ -3921,9 +3949,7 @@ public: void Cleanup() { StopVbcCloseTimeout(); - if (alarm_is_scheduled(suspend_timeout_)) { - alarm_cancel(suspend_timeout_); - } + StopSuspendTimeout(); if (active_group_id_ != bluetooth::groups::kGroupUnknown) { /* Bluetooth turned off while streaming */ @@ -4037,27 +4063,7 @@ public: INT_TO_PTR(active_group_id_)); } - /* Group should tie in time to get requested status */ - uint64_t timeoutMs = kAudioSuspentKeepIsoAliveTimeoutMs; - timeoutMs = osi_property_get_int32(kAudioSuspentKeepIsoAliveTimeoutMsProp, timeoutMs); - - if (stack_config_get_interface()->get_pts_le_audio_disable_ases_before_stopping()) { - timeoutMs += kAudioDisableTimeoutMs; - } - - log::debug("Stream suspend_timeout_ started: {} ms", static_cast<int>(timeoutMs)); - if (alarm_is_scheduled(suspend_timeout_)) { - alarm_cancel(suspend_timeout_); - } - - alarm_set_on_mloop( - suspend_timeout_, timeoutMs, - [](void* data) { - if (instance) { - instance->GroupStop(PTR_TO_INT(data)); - } - }, - INT_TO_PTR(active_group_id_)); + StartSuspendTimeout(); } void OnLocalAudioSourceSuspend() { @@ -4215,6 +4221,7 @@ public: if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { if (IsDirectionAvailableForCurrentConfiguration( group, bluetooth::le_audio::types::kLeAudioDirectionSink)) { + StopSuspendTimeout(); StartSendingAudio(active_group_id_); } else { log::warn( @@ -4255,9 +4262,7 @@ public: case AudioState::IDLE: case AudioState::READY_TO_RELEASE: /* Stream is up just restore it */ - if (alarm_is_scheduled(suspend_timeout_)) { - alarm_cancel(suspend_timeout_); - } + StopSuspendTimeout(); ConfirmLocalAudioSourceStreamingRequest(); bluetooth::le_audio::MetricsCollector::Get()->OnStreamStarted( active_group_id_, configuration_context_type_); @@ -4282,8 +4287,6 @@ public: "r_state: " + ToString(audio_receiver_state_) + ", s_state: " + ToString(audio_sender_state_)); - StartVbcCloseTimeout(); - /* Note: This callback is from audio hal driver. * Bluetooth peer is a Source for Audio Framework. * e.g. Peer is microphone. @@ -4308,6 +4311,11 @@ public: if ((audio_sender_state_ == AudioState::IDLE) || (audio_sender_state_ == AudioState::READY_TO_RELEASE)) { OnAudioSuspend(); + } else { + /* If the local sink direction is used, we want to monitor + * if back channel is actually needed. + */ + StartVbcCloseTimeout(); } log::info("OUT: audio_receiver_state_: {}, audio_sender_state_: {}", @@ -4468,6 +4476,7 @@ public: if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { if (IsDirectionAvailableForCurrentConfiguration( group, bluetooth::le_audio::types::kLeAudioDirectionSource)) { + StopSuspendTimeout(); StartReceivingAudio(active_group_id_); } else { log::warn( @@ -4507,9 +4516,7 @@ public: case AudioState::READY_TO_START: case AudioState::READY_TO_RELEASE: /* Stream is up just restore it */ - if (alarm_is_scheduled(suspend_timeout_)) { - alarm_cancel(suspend_timeout_); - } + StopSuspendTimeout(); ConfirmLocalAudioSinkStreamingRequest(); break; case AudioState::RELEASING: @@ -4604,9 +4611,7 @@ public: return false; } - if (alarm_is_scheduled(suspend_timeout_)) { - alarm_cancel(suspend_timeout_); - } + StopSuspendTimeout(); /* Need to reconfigure stream. At this point pre_configuration_context_type shall be set */ diff --git a/system/bta/le_audio/client_parser.cc b/system/bta/le_audio/client_parser.cc index f3b3b66925..9de6734bc7 100644 --- a/system/bta/le_audio/client_parser.cc +++ b/system/bta/le_audio/client_parser.cc @@ -33,7 +33,6 @@ #include "internal_include/bt_trace.h" #include "le_audio_types.h" #include "le_audio_utils.h" -#include "os/log.h" #include "stack/include/bt_types.h" using bluetooth::le_audio::types::acs_ac_record; diff --git a/system/bta/le_audio/codec_interface.cc b/system/bta/le_audio/codec_interface.cc index b5c75c6e1c..637c77f5bf 100644 --- a/system/bta/le_audio/codec_interface.cc +++ b/system/bta/le_audio/codec_interface.cc @@ -25,8 +25,6 @@ #include <optional> #include <vector> -#include "os/log.h" - namespace bluetooth::le_audio { struct CodecInterface::Impl { diff --git a/system/bta/le_audio/codec_manager.cc b/system/bta/le_audio/codec_manager.cc index fce821417d..117c3a2cec 100644 --- a/system/bta/le_audio/codec_manager.cc +++ b/system/bta/le_audio/codec_manager.cc @@ -31,7 +31,6 @@ #include "le_audio_set_configuration_provider.h" #include "le_audio_utils.h" #include "main/shim/entry.h" -#include "os/log.h" #include "osi/include/properties.h" #include "stack/include/hcimsgs.h" @@ -281,23 +280,47 @@ public: return true; } - AudioSetConfigurations GetSupportedCodecConfigurations( - const CodecManager::UnicastConfigurationRequirements& requirements) const { + std::unique_ptr<AudioSetConfiguration> GetLocalCodecConfigurations( + const CodecManager::UnicastConfigurationRequirements& requirements, + CodecManager::UnicastConfigurationProvider provider) const { + AudioSetConfigurations configs; if (GetCodecLocation() == le_audio::types::CodecLocation::ADSP) { log::verbose("Get offload config for the context type: {}", (int)requirements.audio_context_type); - // TODO: Need to have a mechanism to switch to software session if offload // doesn't support. - return context_type_offload_config_map_.count(requirements.audio_context_type) - ? context_type_offload_config_map_.at(requirements.audio_context_type) - : AudioSetConfigurations(); + configs = context_type_offload_config_map_.count(requirements.audio_context_type) + ? context_type_offload_config_map_.at(requirements.audio_context_type) + : AudioSetConfigurations(); + } else { + log::verbose("Get software config for the context type: {}", + (int)requirements.audio_context_type); + configs = *AudioSetConfigurationProvider::Get()->GetConfigurations( + requirements.audio_context_type); } - log::verbose("Get software config for the context type: {}", - (int)requirements.audio_context_type); - return *AudioSetConfigurationProvider::Get()->GetConfigurations( - requirements.audio_context_type); + if (configs.empty()) { + log::error("No valid configuration matching the requirements: {}", requirements); + PrintDebugState(); + return nullptr; + } + + // Remove the dual bidir SWB config if not supported + if (!IsDualBiDirSwbSupported()) { + configs.erase(std::remove_if(configs.begin(), configs.end(), + [](auto const& el) { + if (el->confs.source.empty()) { + return false; + } + return AudioSetConfigurationProvider::Get() + ->CheckConfigurationIsDualBiDirSwb(*el); + }), + configs.end()); + } + + // Note: For the software configuration provider, we use the provider matcher + // logic to match the proper configuration with group capabilities. + return provider(requirements, &configs); } void PrintDebugState() const { @@ -318,6 +341,10 @@ public: } bool IsUsingCodecExtensibility() const { + if (GetCodecLocation() == types::CodecLocation::HOST) { + return false; + } + auto codec_ext_status = osi_property_get_bool("bluetooth.core.le_audio.codec_extension_aidl.enabled", false) && com::android::bluetooth::flags::leaudio_multicodec_aidl_support(); @@ -334,37 +361,9 @@ public: if (hal_config) { return std::make_unique<AudioSetConfiguration>(*hal_config); } - log::debug( - "No configuration received from AIDL, fall back to static " - "configuration."); + log::debug("No configuration received from AIDL, fall back to static configuration."); } - - auto configs = GetSupportedCodecConfigurations(requirements); - if (configs.empty()) { - log::error("No valid configuration matching the requirements: {}", requirements); - PrintDebugState(); - return nullptr; - } - - // Remove the dual bidir SWB config if not supported - if (!IsDualBiDirSwbSupported()) { - configs.erase(std::remove_if(configs.begin(), configs.end(), - [](auto const& el) { - if (el->confs.source.empty()) { - return false; - } - return AudioSetConfigurationProvider::Get() - ->CheckConfigurationIsDualBiDirSwb(*el); - }), - configs.end()); - } - - // Note: For the only supported right now legacy software configuration - // provider, we use the device group logic to match the proper - // configuration with group capabilities. Note that this path only - // supports the LC3 codec format. For the multicodec support we should - // rely on the configuration matcher behind the AIDL interface. - return provider(requirements, &configs); + return GetLocalCodecConfigurations(requirements, provider); } bool CheckCodecConfigIsBiDirSwb(const AudioSetConfiguration& config) { diff --git a/system/bta/le_audio/codec_manager_test.cc b/system/bta/le_audio/codec_manager_test.cc index d72d587880..5770fdbea4 100644 --- a/system/bta/le_audio/codec_manager_test.cc +++ b/system/bta/le_audio/codec_manager_test.cc @@ -265,6 +265,8 @@ void set_mock_offload_capabilities(const std::vector<AudioSetConfiguration>& cap } static constexpr char kPropLeAudioOffloadSupported[] = "ro.bluetooth.leaudio_offload.supported"; +static constexpr char kPropLeAudioCodecExtensibility[] = + "bluetooth.core.le_audio.codec_extension_aidl.enabled"; static constexpr char kPropLeAudioOffloadDisabled[] = "persist.bluetooth.leaudio_offload.disabled"; static constexpr char kPropLeAudioBidirSwbSupported[] = "bluetooth.leaudio.dual_bidirection_swb.supported"; @@ -823,6 +825,10 @@ public: // Allow for bidir SWB configurations osi_property_set_bool(kPropLeAudioBidirSwbSupported, true); + // Codec extensibility disabled by default + com::android::bluetooth::flags::provider_->leaudio_multicodec_aidl_support(false); + osi_property_set_bool(kPropLeAudioCodecExtensibility, false); + CodecManagerTestBase::SetUp(); } }; @@ -837,6 +843,10 @@ public: // Do not allow for bidir SWB configurations osi_property_set_bool(kPropLeAudioBidirSwbSupported, false); + // Codec extensibility disabled by default + com::android::bluetooth::flags::provider_->leaudio_multicodec_aidl_support(false); + osi_property_set_bool(kPropLeAudioCodecExtensibility, false); + CodecManagerTestBase::SetUp(); } }; @@ -1295,4 +1305,28 @@ TEST_F(CodecManagerTestHost, test_dont_update_broadcast_offloader) { ASSERT_FALSE(was_called); } +TEST_F(CodecManagerTestHost, test_dont_call_hal_for_config) { + com::android::bluetooth::flags::provider_->leaudio_multicodec_aidl_support(true); + osi_property_set_bool(kPropLeAudioCodecExtensibility, true); + + // Set the offloader capabilities + std::vector<AudioSetConfiguration> offload_capabilities; + set_mock_offload_capabilities(offload_capabilities); + + const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {}; + codec_manager->Start(offloading_preference); + codec_manager->UpdateActiveUnicastAudioHalClient(mock_le_audio_source_hal_client_, + mock_le_audio_sink_hal_client_, true); + + EXPECT_CALL(*mock_le_audio_source_hal_client_, GetUnicastConfig(_)).Times(0); + codec_manager->GetCodecConfig( + {.audio_context_type = types::LeAudioContextType::MEDIA}, + [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/, + const set_configurations::AudioSetConfigurations* /*confs*/) + -> std::unique_ptr<set_configurations::AudioSetConfiguration> { + // In this case the chosen configuration doesn't matter - select none + return nullptr; + }); +} + } // namespace bluetooth::le_audio diff --git a/system/bta/le_audio/content_control_id_keeper.cc b/system/bta/le_audio/content_control_id_keeper.cc index cfda2dedc2..f4ca933f06 100644 --- a/system/bta/le_audio/content_control_id_keeper.cc +++ b/system/bta/le_audio/content_control_id_keeper.cc @@ -24,7 +24,6 @@ #include "common/strings.h" #include "le_audio_types.h" -#include "os/log.h" namespace { diff --git a/system/bta/le_audio/devices.h b/system/bta/le_audio/devices.h index 1f972aae85..0707bae4b4 100644 --- a/system/bta/le_audio/devices.h +++ b/system/bta/le_audio/devices.h @@ -26,7 +26,6 @@ #include "gatt_api.h" #include "gmap_client.h" #include "le_audio_types.h" -#include "os/log.h" #include "osi/include/alarm.h" #include "raw_address.h" diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc index 1ad0684ce6..11480961b8 100644 --- a/system/bta/le_audio/devices_test.cc +++ b/system/bta/le_audio/devices_test.cc @@ -32,7 +32,6 @@ #include "le_audio_types.h" #include "mock_codec_manager.h" #include "mock_csis_client.h" -#include "os/log.h" #include "stack/btm/btm_int_types.h" #include "test/mock/mock_main_shim_entry.h" diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc index 333f4e8573..05a26249ac 100644 --- a/system/bta/le_audio/le_audio_client_test.cc +++ b/system/bta/le_audio/le_audio_client_test.cc @@ -1442,6 +1442,7 @@ protected: void SetUp() override { __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE); init_message_loop_thread(); + reset_mock_function_count_map(); ON_CALL(controller_, SupportsBleConnectedIsochronousStreamCentral).WillByDefault(Return(true)); ON_CALL(controller_, SupportsBleConnectedIsochronousStreamPeripheral) .WillByDefault(Return(true)); @@ -9914,6 +9915,83 @@ TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) { Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_); } +TEST_F(UnicastTest, SwitchBetweenMicrophoneAndSoundEffectScenario) { + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + /* Scenario: + * 1. User starts Recording - this creates bidiretional CISes + * 2. User stops recording - this starts suspend timeout (500ms) + * 3. Since user touch the screen it generates touch tone - this shall reuse existing CISes when + * it happens 500ms before stop + */ + SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo, + codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt, + default_channel_cnt, 0x0024, 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); + + // 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(); + + // When the local audio source resumes we have no knowledge of recording + EXPECT_CALL(mock_state_machine_, + StartStream(_, bluetooth::le_audio::types::LeAudioContextType::LIVE, _, _)) + .Times(1); + + log::info("Start Microphone recording - bidirectional CISes are expected"); + UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC); + LocalAudioSinkResume(); + + ASSERT_EQ(0, get_func_call_count("alarm_set_on_mloop")); + SyncOnMainLoop(); + + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + // Verify Data transfer on one audio source cis + uint8_t cis_count_out = 0; + uint8_t cis_count_in = 1; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 60); + + log::info("Suspend microphone recording - suspend timeout is not fired"); + LocalAudioSinkSuspend(); + SyncOnMainLoop(); + + // VBC and Suspend + ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop")); + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + + log::info("Resume local source with touch tone - expect suspend timeout to be canceled"); + + UpdateLocalSourceMetadata(AUDIO_USAGE_ASSISTANCE_SONIFICATION, AUDIO_CONTENT_TYPE_SONIFICATION); + LocalAudioSourceResume(); + SyncOnMainLoop(); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + + auto group = streaming_groups.at(group_id); + group->PrintDebugState(); + + // Verify Data transfer on one audio source and sink cis + cis_count_out = 1; + cis_count_in = 0; + TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920, 60); +} + /* When a certain context is unavailable and not supported we should stream * as UNSPECIFIED for the backwards compatibility. * Since UNSPECIFIED is available, put the UNSPECIFIED into the metadata instead diff --git a/system/bta/le_audio/le_audio_health_status.cc b/system/bta/le_audio/le_audio_health_status.cc index 3b349e8179..5a2c2feb92 100644 --- a/system/bta/le_audio/le_audio_health_status.cc +++ b/system/bta/le_audio/le_audio_health_status.cc @@ -23,7 +23,6 @@ #include "bta/include/bta_groups.h" #include "common/strings.h" #include "main/shim/metrics_api.h" -#include "os/log.h" #include "osi/include/properties.h" using bluetooth::common::ToString; diff --git a/system/bta/le_audio/le_audio_log_history.cc b/system/bta/le_audio/le_audio_log_history.cc index 0022d7b7da..22fd939994 100644 --- a/system/bta/le_audio/le_audio_log_history.cc +++ b/system/bta/le_audio/le_audio_log_history.cc @@ -25,7 +25,7 @@ #include "common/circular_buffer.h" #include "common/strings.h" #include "main/shim/dumpsys.h" -#include "os/log.h" +#include "os/logging/log_adapter.h" #include "osi/include/osi.h" #include "osi/include/properties.h" diff --git a/system/bta/le_audio/le_audio_set_configuration_provider_json.cc b/system/bta/le_audio/le_audio_set_configuration_provider_json.cc index 169943323c..3b8643152d 100644 --- a/system/bta/le_audio/le_audio_set_configuration_provider_json.cc +++ b/system/bta/le_audio/le_audio_set_configuration_provider_json.cc @@ -29,7 +29,6 @@ #include "flatbuffers/util.h" #include "le_audio/le_audio_types.h" #include "le_audio_set_configuration_provider.h" -#include "os/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" diff --git a/system/bta/le_audio/le_audio_utils.cc b/system/bta/le_audio/le_audio_utils.cc index 2e29fd1e03..719d017607 100644 --- a/system/bta/le_audio/le_audio_utils.cc +++ b/system/bta/le_audio/le_audio_utils.cc @@ -20,7 +20,6 @@ #include "common/strings.h" #include "le_audio_types.h" -#include "os/log.h" using bluetooth::common::ToString; using bluetooth::le_audio::types::AudioContexts; diff --git a/system/bta/le_audio/storage_helper.cc b/system/bta/le_audio/storage_helper.cc index b9f24233c3..916c8249b1 100644 --- a/system/bta/le_audio/storage_helper.cc +++ b/system/bta/le_audio/storage_helper.cc @@ -23,7 +23,6 @@ #include "client_parser.h" #include "common/strings.h" #include "le_audio_types.h" -#include "os/log.h" #include "stack/include/bt_types.h" // TODO(b/369381361) Enfore -Wmissing-prototypes diff --git a/system/bta/ras/ras_utils.cc b/system/bta/ras/ras_utils.cc index d27a6bf697..2a9b3b9c88 100644 --- a/system/bta/ras/ras_utils.cc +++ b/system/bta/ras/ras_utils.cc @@ -21,7 +21,6 @@ #include "bta/include/bta_gatt_api.h" #include "bta/include/bta_ras_api.h" #include "bta/ras/ras_types.h" -#include "os/log.h" #include "stack/include/bt_types.h" #include "stack/include/btm_ble_addr.h" #include "stack/include/gap_api.h" diff --git a/system/bta/sys/bta_sys_main.cc b/system/bta/sys/bta_sys_main.cc index 4e5ad74d52..524f750ff7 100644 --- a/system/bta/sys/bta_sys_main.cc +++ b/system/bta/sys/bta_sys_main.cc @@ -33,7 +33,6 @@ #include "bta/sys/bta_sys_int.h" #include "include/hardware/bluetooth.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/bta/test/common/fake_osi.h b/system/bta/test/common/fake_osi.h index 9eceafaa91..1a9456d628 100644 --- a/system/bta/test/common/fake_osi.h +++ b/system/bta/test/common/fake_osi.h @@ -21,6 +21,7 @@ #include "osi/include/alarm.h" struct fake_osi_alarm_set_on_mloop { + alarm_t* alarm; uint64_t interval_ms{0}; alarm_callback_t cb{}; void* data{nullptr}; diff --git a/system/bta/vc/device.cc b/system/bta/vc/device.cc index ec2088981e..f4f016f2d9 100644 --- a/system/bta/vc/device.cc +++ b/system/bta/vc/device.cc @@ -25,7 +25,6 @@ #include "bta/include/bta_gatt_queue.h" #include "bta/vc/devices.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "os/logging/log_adapter.h" #include "stack/btm/btm_sec.h" #include "stack/include/bt_types.h" diff --git a/system/bta/vc/vc.cc b/system/bta/vc/vc.cc index 6a449c74c3..2c415a59c0 100644 --- a/system/bta/vc/vc.cc +++ b/system/bta/vc/vc.cc @@ -33,7 +33,6 @@ #include "bta/le_audio/le_audio_types.h" #include "bta/vc/devices.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/osi.h" #include "stack/btm/btm_sec.h" #include "stack/include/bt_types.h" diff --git a/system/btcore/src/module.cc b/system/btcore/src/module.cc index 3f809d4d5d..ec34b32636 100644 --- a/system/btcore/src/module.cc +++ b/system/btcore/src/module.cc @@ -28,7 +28,6 @@ #include <unordered_map> #include "common/message_loop_thread.h" -#include "os/log.h" using bluetooth::common::MessageLoopThread; using namespace bluetooth; diff --git a/system/btcore/src/osi_module.cc b/system/btcore/src/osi_module.cc index 22d8f05398..638748fe03 100644 --- a/system/btcore/src/osi_module.cc +++ b/system/btcore/src/osi_module.cc @@ -21,7 +21,6 @@ #include "btcore/include/osi_module.h" #include "btcore/include/module.h" -#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/future.h" #include "osi/include/osi.h" diff --git a/system/btif/Android.bp b/system/btif/Android.bp index 9b22ee4784..2d3d40e3fd 100644 --- a/system/btif/Android.bp +++ b/system/btif/Android.bp @@ -597,8 +597,6 @@ cc_test { "libbt-platform-protos-lite", "libbt-sbc-decoder", "libbt-sbc-encoder", - "libbt-stack", - "libbt-stack-core", "libbtdevice", "libbtif", "libbtif-core", diff --git a/system/btif/avrcp/avrcp_service.cc b/system/btif/avrcp/avrcp_service.cc index 577628eb2b..ce1b1ce577 100644 --- a/system/btif/avrcp/avrcp_service.cc +++ b/system/btif/avrcp/avrcp_service.cc @@ -32,6 +32,7 @@ #include "btif/include/btif_av.h" #include "btif/include/btif_common.h" #include "osi/include/osi.h" +#include "profile/avrcp/avrcp_config.h" #include "profile/avrcp/device.h" #include "stack/include/a2dp_api.h" #include "stack/include/bt_hdr.h" @@ -100,7 +101,7 @@ public: return AVRC_Open(p_handle, p_ccb, bd_addr); } - uint16_t OpenBrowse(uint8_t handle, uint8_t conn_role) override { + uint16_t OpenBrowse(uint8_t handle, tAVCT_ROLE conn_role) override { return AVRC_OpenBrowse(handle, conn_role); } diff --git a/system/btif/co/bta_pan_co.cc b/system/btif/co/bta_pan_co.cc index bdc0ac397b..db84d8bd34 100644 --- a/system/btif/co/bta_pan_co.cc +++ b/system/btif/co/bta_pan_co.cc @@ -36,7 +36,6 @@ #include "btif_pan_internal.h" #include "btif_sock_thread.h" #include "btif_util.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "pan_api.h" #include "stack/include/bt_hdr.h" diff --git a/system/btif/include/btif_common.h b/system/btif/include/btif_common.h index 64433579f0..109dd49893 100644 --- a/system/btif/include/btif_common.h +++ b/system/btif/include/btif_common.h @@ -30,7 +30,6 @@ #include "abstract_message_loop.h" #include "bta/include/bta_api.h" -#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc index f246ca1be8..c4bb371e80 100644 --- a/system/btif/src/bluetooth.cc +++ b/system/btif/src/bluetooth.cc @@ -100,8 +100,9 @@ #include "osi/include/wakelock.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sco_hfp_hal.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/include/a2dp_api.h" +#include "stack/include/avct_api.h" #include "stack/include/avdt_api.h" #include "stack/include/btm_client_interface.h" #include "stack/include/btm_status.h" @@ -886,6 +887,7 @@ static void dump(int fd, const char** arguments) { VolumeControl::DebugDump(fd); connection_manager::dump(fd); bluetooth::bqr::DebugDump(fd); + AVCT_Dumpsys(fd); PAN_Dumpsys(fd); DumpsysHid(fd); DumpsysBtaDm(fd); diff --git a/system/btif/src/btif_a2dp.cc b/system/btif/src/btif_a2dp.cc index f8036bf8c8..01127c3a68 100644 --- a/system/btif/src/btif_a2dp.cc +++ b/system/btif/src/btif_a2dp.cc @@ -130,6 +130,8 @@ void btif_a2dp_on_offload_started(const RawAddress& peer_addr, tBTA_AV_STATUS st switch (status) { case BTA_AV_SUCCESS: + // Call required to update the session state for metrics. + btif_a2dp_source_start_audio_req(); ack = BluetoothAudioStatus::SUCCESS; break; case BTA_AV_FAIL_RESOURCES: diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc index 61dedb5bf3..ae296a4249 100644 --- a/system/btif/src/btif_a2dp_source.cc +++ b/system/btif/src/btif_a2dp_source.cc @@ -55,6 +55,7 @@ #include "stack/include/bt_hdr.h" #include "stack/include/btm_client_interface.h" #include "stack/include/btm_status.h" +#include "stack/include/main_thread.h" #include "types/raw_address.h" using bluetooth::audio::a2dp::BluetoothAudioStatus; @@ -227,9 +228,14 @@ private: BtifA2dpSource::RunState state_; }; +/// Source worker thread created to run the CPU heavy encoder calls. +/// Exactly three functions are executed on this thread: +/// - btif_a2dp_source_audio_handle_timer +/// - btif_a2dp_source_read_callback +/// - btif_a2dp_source_enqueue_callback static bluetooth::common::MessageLoopThread btif_a2dp_source_thread("bt_a2dp_source_worker_thread"); -static BtifA2dpSource btif_a2dp_source_cb; +static BtifA2dpSource btif_a2dp_source_cb; static uint8_t btif_a2dp_source_dynamic_audio_buffer_size = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ; static void btif_a2dp_source_init_delayed(void); @@ -313,12 +319,19 @@ static void btif_a2dp_source_accumulate_stats(BtifMediaStats* src, BtifMediaStat src->Reset(); } +/// Select the thread to run a2dp source actions on (a2dp encoder excluded). +static bluetooth::common::MessageLoopThread* local_thread() { + return com::android::bluetooth::flags::a2dp_source_threading_fix() ? get_main_thread() + : &btif_a2dp_source_thread; +} + bool btif_a2dp_source_init(void) { log::info(""); // Start A2DP Source media task btif_a2dp_source_thread.StartUp(); - btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed)); + + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_init_delayed)); return true; } @@ -384,8 +397,7 @@ static void btif_a2dp_source_init_delayed(void) { // the provider needs to be initialized earlier in order to ensure // get_a2dp_configuration and parse_a2dp_configuration can be // invoked before the stream is started. - bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port, - btif_av_is_a2dp_offload_enabled()); + bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled()); } static bool btif_a2dp_source_startup(void) { @@ -401,7 +413,7 @@ static bool btif_a2dp_source_startup(void) { btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX); // Schedule the rest of the operations - btif_a2dp_source_thread.DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed)); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_startup_delayed)); return true; } @@ -413,7 +425,7 @@ static void btif_a2dp_source_startup_delayed() { log::fatal("unable to enable real time scheduling"); #endif } - if (!bluetooth::audio::a2dp::init(&btif_a2dp_source_thread, &a2dp_audio_port, + if (!bluetooth::audio::a2dp::init(local_thread(), &a2dp_audio_port, btif_av_is_a2dp_offload_enabled())) { log::warn("Failed to setup the bluetooth audio HAL"); } @@ -426,7 +438,7 @@ bool btif_a2dp_source_start_session(const RawAddress& peer_address, btif_a2dp_source_audio_tx_flush_req(); - if (btif_a2dp_source_thread.DoInThread( + if (local_thread()->DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_start_session_delayed, peer_address, std::move(peer_ready_promise)))) { return true; @@ -491,8 +503,8 @@ bool btif_a2dp_source_restart_session(const RawAddress& old_peer_address, bool btif_a2dp_source_end_session(const RawAddress& peer_address) { log::info("peer_address={} state={}", peer_address, btif_a2dp_source_cb.StateStr()); - btif_a2dp_source_thread.DoInThread( - FROM_HERE, base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address)); + local_thread()->DoInThread(FROM_HERE, + base::BindOnce(&btif_a2dp_source_end_session_delayed, peer_address)); btif_a2dp_source_cleanup_codec(); return true; } @@ -518,7 +530,7 @@ static void btif_a2dp_source_end_session_delayed(const RawAddress& peer_address) void btif_a2dp_source_allow_low_latency_audio(bool allowed) { log::info("allowed={}", allowed); - btif_a2dp_source_thread.DoInThread( + local_thread()->DoInThread( FROM_HERE, base::BindOnce(bluetooth::audio::a2dp::set_audio_low_latency_mode_allowed, allowed)); } @@ -534,9 +546,8 @@ 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); - btif_a2dp_source_thread.DoInThread( - FROM_HERE, - base::BindOnce(&btif_a2dp_source_shutdown_delayed, std::move(shutdown_complete_promise))); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_shutdown_delayed, + std::move(shutdown_complete_promise))); } static void btif_a2dp_source_shutdown_delayed(std::promise<void> shutdown_complete_promise) { @@ -614,8 +625,9 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) { log::error("Cannot stream audio: cannot set active peer to {}", peer_address); return; } - btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface(peer_address); - if (btif_a2dp_source_cb.encoder_interface == nullptr) { + + const tA2DP_ENCODER_INTERFACE* encoder_interface = bta_av_co_get_encoder_interface(peer_address); + if (encoder_interface == nullptr) { log::error("Cannot stream audio: no source encoder interface"); return; } @@ -626,11 +638,11 @@ static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) { return; } - btif_a2dp_source_cb.encoder_interface->encoder_init(&peer_params, a2dp_codec_config, - btif_a2dp_source_read_callback, - btif_a2dp_source_enqueue_callback); + encoder_interface->encoder_init(&peer_params, a2dp_codec_config, btif_a2dp_source_read_callback, + btif_a2dp_source_enqueue_callback); // Save a local copy of the encoder_interval_ms + btif_a2dp_source_cb.encoder_interface = encoder_interface; btif_a2dp_source_cb.encoder_interval_ms = btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(); @@ -645,8 +657,7 @@ static void btif_a2dp_source_cleanup_codec() { log::info("state={}", btif_a2dp_source_cb.StateStr()); // Must stop media task first before cleaning up the encoder btif_a2dp_source_stop_audio_req(); - btif_a2dp_source_thread.DoInThread(FROM_HERE, - base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed)); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_cleanup_codec_delayed)); } static void btif_a2dp_source_cleanup_codec_delayed() { @@ -660,15 +671,13 @@ static void btif_a2dp_source_cleanup_codec_delayed() { void btif_a2dp_source_start_audio_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); - btif_a2dp_source_thread.DoInThread(FROM_HERE, - base::BindOnce(&btif_a2dp_source_audio_tx_start_event)); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_start_event)); } void btif_a2dp_source_stop_audio_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); - btif_a2dp_source_thread.DoInThread(FROM_HERE, - base::BindOnce(&btif_a2dp_source_audio_tx_stop_event)); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_stop_event)); } void btif_a2dp_source_encoder_user_config_update_req( @@ -677,7 +686,8 @@ void btif_a2dp_source_encoder_user_config_update_req( std::promise<void> peer_ready_promise) { log::info("peer_address={} state={} {} codec_preference(s)", peer_address, btif_a2dp_source_cb.StateStr(), codec_user_preferences.size()); - if (!btif_a2dp_source_thread.DoInThread( + + if (!local_thread()->DoInThread( FROM_HERE, base::BindOnce(&btif_a2dp_source_encoder_user_config_update_event, peer_address, codec_user_preferences, std::move(peer_ready_promise)))) { @@ -723,9 +733,8 @@ static void btif_a2dp_source_encoder_user_config_update_event( void btif_a2dp_source_feeding_update_req(const btav_a2dp_codec_config_t& codec_audio_config) { log::info("state={}", btif_a2dp_source_cb.StateStr()); - btif_a2dp_source_thread.DoInThread( - FROM_HERE, - base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, codec_audio_config)); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_feeding_update_event, + codec_audio_config)); } static void btif_a2dp_source_audio_feeding_update_event( @@ -761,7 +770,6 @@ void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) { } } else { bluetooth::audio::a2dp::ack_stream_suspended(BluetoothAudioStatus::SUCCESS); - return; } if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) { @@ -797,7 +805,6 @@ void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) { } } else if (btif_av_is_a2dp_offload_running()) { bluetooth::audio::a2dp::ack_stream_suspended(BluetoothAudioStatus::SUCCESS); - return; } // ensure tx frames are immediately suspended @@ -819,60 +826,54 @@ static void btif_a2dp_source_audio_tx_start_event(void) { log::info("streaming {} state={}", btif_a2dp_source_is_streaming(), btif_a2dp_source_cb.StateStr()); + btif_a2dp_source_cb.stats.Reset(); + btif_a2dp_source_cb.stats.session_start_us = bluetooth::common::time_get_os_boottime_us(); + btif_a2dp_source_cb.stats.session_end_us = 0; + + A2dpCodecConfig* codec_config = bta_av_get_a2dp_current_codec(); + if (codec_config != nullptr) { + btif_a2dp_source_cb.stats.codec_index = codec_config->codecIndex(); + } + if (btif_av_is_a2dp_offload_running()) { return; } - /* Reset the media feeding state */ log::assert_that(btif_a2dp_source_cb.encoder_interface != nullptr, "assert failed: btif_a2dp_source_cb.encoder_interface != nullptr"); - btif_a2dp_source_cb.encoder_interface->feeding_reset(); - log::verbose("starting timer {} ms", + log::verbose("starting media encoder timer with interval {}ms", btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms()); - /* audio engine starting, reset tx suspended flag */ - btif_a2dp_source_cb.tx_flush = false; - wakelock_acquire(); + btif_a2dp_source_cb.encoder_interface->feeding_reset(); + btif_a2dp_source_cb.tx_flush = false; + btif_a2dp_source_cb.sw_audio_is_encoding = true; btif_a2dp_source_cb.media_alarm.SchedulePeriodic( btif_a2dp_source_thread.GetWeakPtr(), FROM_HERE, base::BindRepeating(&btif_a2dp_source_audio_handle_timer), std::chrono::milliseconds( btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms())); - btif_a2dp_source_cb.sw_audio_is_encoding = true; - - btif_a2dp_source_cb.stats.Reset(); - // Assign session_start_us to 1 when - // bluetooth::common::time_get_os_boottime_us() is 0 to indicate - // btif_a2dp_source_start_audio_req() has been called - btif_a2dp_source_cb.stats.session_start_us = bluetooth::common::time_get_os_boottime_us(); - if (btif_a2dp_source_cb.stats.session_start_us == 0) { - btif_a2dp_source_cb.stats.session_start_us = 1; - } - btif_a2dp_source_cb.stats.session_end_us = 0; - A2dpCodecConfig* codec_config = bta_av_get_a2dp_current_codec(); - if (codec_config != nullptr) { - btif_a2dp_source_cb.stats.codec_index = codec_config->codecIndex(); - } } static void btif_a2dp_source_audio_tx_stop_event(void) { log::info("streaming {} state={}", btif_a2dp_source_is_streaming(), btif_a2dp_source_cb.StateStr()); + btif_a2dp_source_cb.stats.session_end_us = bluetooth::common::time_get_os_boottime_us(); + + btif_a2dp_source_update_metrics(); + btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats, + &btif_a2dp_source_cb.accumulated_stats); + if (btif_av_is_a2dp_offload_running()) { return; } + if (!btif_a2dp_source_is_streaming()) { return; } - btif_a2dp_source_cb.stats.session_end_us = bluetooth::common::time_get_os_boottime_us(); - btif_a2dp_source_update_metrics(); - btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats, - &btif_a2dp_source_cb.accumulated_stats); - /* Drain data still left in the queue */ static constexpr size_t AUDIO_STREAM_OUTPUT_BUFFER_SZ = 28 * 512; uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2]; @@ -893,39 +894,48 @@ static void btif_a2dp_source_audio_tx_stop_event(void) { } } +/// Periodic task responsible for encoding the audio stream and forwarding +/// to the remote device. It will read PCM samples from the HAL provided FMQ, +/// encode them into audio frames. Runs on the source worker thread. +/// +/// The timer driving the periodic task is cancelled before any state cleanup +/// when the stream is ended. static void btif_a2dp_source_audio_handle_timer(void) { - if (btif_av_is_a2dp_offload_running()) { - return; - } - uint64_t timestamp_us = bluetooth::common::time_get_audio_server_tick_us(); uint64_t stats_timestamp_us = bluetooth::common::time_get_os_boottime_us(); log_tstamps_us("A2DP Source tx scheduling timer", timestamp_us); - if (!btif_a2dp_source_is_streaming()) { - log::error("ERROR Media task Scheduled after Suspend"); - return; - } log::assert_that(btif_a2dp_source_cb.encoder_interface != nullptr, "assert failed: btif_a2dp_source_cb.encoder_interface != nullptr"); + size_t transmit_queue_length = fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue); + #ifdef __ANDROID__ ATRACE_INT("btif TX queue", transmit_queue_length); #endif + if (btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length != nullptr) { btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length(transmit_queue_length); } + btif_a2dp_source_cb.encoder_interface->send_frames(timestamp_us); + bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO); update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats, stats_timestamp_us, btif_a2dp_source_cb.encoder_interval_ms * 1000); } +/// Callback invoked by the encoder for reading PCM audio data from the +/// Bluetooth Audio HAL. Runs on the source worker thread. static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) { + if (!btif_a2dp_source_cb.sw_audio_is_encoding) { + return 0; + } + uint32_t bytes_read = bluetooth::audio::a2dp::read(p_buf, len); - if (btif_a2dp_source_cb.sw_audio_is_encoding && bytes_read < len) { + if (bytes_read < len) { log::warn("UNDERFLOW: ONLY READ {} BYTES OUT OF {}", bytes_read, len); btif_a2dp_source_cb.stats.media_read_total_underflow_bytes += (len - bytes_read); btif_a2dp_source_cb.stats.media_read_total_underflow_count++; @@ -938,17 +948,13 @@ static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) { return bytes_read; } +/// Callback invoked by the encoder for sending encoded audio frames to the +/// remote Bluetooth device. Runs on the source worker thread. static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n, uint32_t /*bytes_read*/) { uint64_t now_us = bluetooth::common::time_get_os_boottime_us(); - /* Check if timer was stopped (media task stopped) */ - if (!btif_a2dp_source_is_streaming()) { - osi_free(p_buf); - return false; - } - - /* Check if the transmission queue has been flushed */ + // Check if the transmission queue has been flushed. if (btif_a2dp_source_cb.tx_flush) { log::verbose("tx suspended, discarded frame"); @@ -1011,12 +1017,10 @@ static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n, } } - /* Update the statistics */ + // Update the statistics. btif_a2dp_source_cb.stats.tx_queue_total_frames += frames_n; btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet = std::max(frames_n, btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet); - log::assert_that(btif_a2dp_source_cb.encoder_interface != nullptr, - "assert failed: btif_a2dp_source_cb.encoder_interface != nullptr"); fixed_queue_enqueue(btif_a2dp_source_cb.tx_audio_queue, p_buf); @@ -1043,8 +1047,7 @@ static void btif_a2dp_source_audio_tx_flush_event(void) { static bool btif_a2dp_source_audio_tx_flush_req(void) { log::info("state={}", btif_a2dp_source_cb.StateStr()); - btif_a2dp_source_thread.DoInThread(FROM_HERE, - base::BindOnce(&btif_a2dp_source_audio_tx_flush_event)); + local_thread()->DoInThread(FROM_HERE, base::BindOnce(&btif_a2dp_source_audio_tx_flush_event)); return true; } @@ -1254,15 +1257,11 @@ static void btif_a2dp_source_update_metrics(void) { A2dpSessionMetrics metrics; metrics.codec_index = stats.codec_index; metrics.is_a2dp_offload = btif_av_is_a2dp_offload_running(); + // session_start_us is 0 when btif_a2dp_source_start_audio_req() is not called // mark the metric duration as invalid (-1) in this case if (stats.session_start_us != 0) { - int64_t session_end_us = stats.session_end_us == 0 - ? bluetooth::common::time_get_os_boottime_us() - : stats.session_end_us; - if (static_cast<uint64_t>(session_end_us) > stats.session_start_us) { - metrics.audio_duration_ms = (session_end_us - stats.session_start_us) / 1000; - } + metrics.audio_duration_ms = (stats.session_end_us - stats.session_start_us) / 1000; } if (enqueue_stats.total_updates > 1) { diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index c62d54c281..2132172e48 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -52,6 +52,7 @@ #include "device/include/device_iot_config.h" #include "hardware/bt_av.h" #include "include/hardware/bt_rc.h" +#include "os/logging/log_adapter.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index 2de9feb1ed..e01e2d8d75 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -1283,6 +1283,9 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { case BTA_HH_API_ERR_EVT: log::error("BTA_HH API_ERR"); break; + case BTA_HH_DATA_EVT: + // data output is sent - do nothing. + break; default: log::warn("Unhandled event: {}", event); break; diff --git a/system/btif/src/btif_profile_queue.cc b/system/btif/src/btif_profile_queue.cc index b640c70d02..15237abe75 100644 --- a/system/btif/src/btif_profile_queue.cc +++ b/system/btif/src/btif_profile_queue.cc @@ -30,7 +30,6 @@ #include <base/functional/bind.h> #include <base/functional/callback.h> -#include <base/strings/stringprintf.h> #include <bluetooth/log.h> #include <string.h> @@ -53,8 +52,7 @@ public: : address_(address), uuid_(uuid), busy_(false), connect_cb_(connect_cb) {} std::string ToString() const { - return base::StringPrintf("address=%s UUID=%04X busy=%s", ADDRESS_TO_LOGGABLE_CSTR(address_), - uuid_, (busy_) ? "true" : "false"); + return fmt::format("address={} UUID={:04X} busy={}", address_, uuid_, busy_); } const RawAddress& address() const { return address_; } diff --git a/system/btif/src/btif_rc.cc b/system/btif/src/btif_rc.cc index a059d5a05f..cf244403b1 100644 --- a/system/btif/src/btif_rc.cc +++ b/system/btif/src/btif_rc.cc @@ -44,6 +44,7 @@ #include "btif_common.h" #include "btif_util.h" #include "device/include/interop.h" +#include "os/logging/log_adapter.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "osi/include/list.h" diff --git a/system/build/Android.bp b/system/build/Android.bp index fd6636b0c5..13f1ccccf5 100644 --- a/system/build/Android.bp +++ b/system/build/Android.bp @@ -11,6 +11,7 @@ cc_defaults { name: "fluoride_defaults", defaults: [ "bluetooth_cflags", + "bluetooth_tidy", ], cflags: [ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))", diff --git a/system/common/base_bind_unittest.cc b/system/common/base_bind_unittest.cc index d31ea01642..b4f35f53e4 100644 --- a/system/common/base_bind_unittest.cc +++ b/system/common/base_bind_unittest.cc @@ -24,8 +24,6 @@ #include <memory> #include <mutex> -#include "os/log.h" - class BaseBindThreadTest : public ::testing::Test { public: protected: diff --git a/system/device/src/device_iot_config.cc b/system/device/src/device_iot_config.cc index 0918a54f7b..2da612ac47 100644 --- a/system/device/src/device_iot_config.cc +++ b/system/device/src/device_iot_config.cc @@ -32,7 +32,6 @@ #include "device_iot_config_int.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" diff --git a/system/device/src/device_iot_config_int.cc b/system/device/src/device_iot_config_int.cc index 60f2d884bd..33b5f8106d 100644 --- a/system/device/src/device_iot_config_int.cc +++ b/system/device/src/device_iot_config_int.cc @@ -32,7 +32,6 @@ #include "btcore/include/module.h" #include "btif/include/btif_common.h" #include "device/include/device_iot_config.h" -#include "os/log.h" #include "osi/include/alarm.h" #include "osi/include/config.h" #include "osi/include/future.h" diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc index 78b1b70b34..c45031a7b0 100644 --- a/system/device/src/interop.cc +++ b/system/device/src/interop.cc @@ -40,7 +40,6 @@ #include "btif/include/btif_storage.h" #include "device/include/interop_config.h" #include "device/include/interop_database.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "osi/include/config.h" diff --git a/system/gd/Android.bp b/system/gd/Android.bp index 5f67289b2f..579aae7d44 100644 --- a/system/gd/Android.bp +++ b/system/gd/Android.bp @@ -12,9 +12,7 @@ cc_defaults { name: "gd_defaults", defaults: [ "bluetooth_cflags", - ], - tidy_checks: [ - "-performance-unnecessary-value-param", + "bluetooth_tidy", ], target: { android: { @@ -39,56 +37,6 @@ cc_defaults { header_libs: ["jni_headers"], } -cc_defaults { - name: "gd_clang_tidy", - tidy: true, - tidy_checks: [ - "-bugprone*", - "-cert-dcl21-cpp", // warning: overloaded returns a non-constant object instead of a constant object type - "-cert-dcl59-cpp", // warning: do not use unnamed namespaces in header files - "-cert-msc30-c", // warning: rand() has limited randomness; use C++11 random library instead - "-cert-msc50-cpp", // warning: rand() has limited randomness; use C++11 random library instead - "-cert-oop54-cpp", // warning: operator=() does not handle self-assignment properly - "-google*", - "-performance*", - "clang-analyzer-core.CallAndMessage", - "clang-analyzer-optin.cplusplus.UninitializedObject", - ], - tidy_checks_as_errors: [ - "clang-analyzer-core.CallAndMessage", - "clang-analyzer-optin.cplusplus.UninitializedObject", - "cppcoreguidelines-pro-type-member-init", - ], - tidy_flags: [ - "--header-filter=^.*packages/modules/Bluetooth/system/.*.h$", - - "--extra-arg-before=-Xclang", - "--extra-arg-before=-analyzer-config", - - "--extra-arg-before=-Xclang", - "--extra-arg-before=optin.cplusplus.UninitializedObject:Pedantic=true", - - "--extra-arg-before=-Xclang", - "--extra-arg-before=-analyzer-config", - - "--extra-arg-before=-Xclang", - "--extra-arg-before=optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true", - - ], -} - -// Clang is targeted for android core libraries but other base libraries -// may not support clang tidy recommendations (e.g. MacOS) -cc_defaults { - name: "gd_clang_tidy_ignore_android", - tidy: true, - tidy_checks: [ - "-android-cloexec-accept", // warning: prefer accept4() to accept() because accept4() allows SOCK_CLOEXEC - "-android-cloexec-pipe2", // warning: 'pipe2' should use O_CLOEXEC where possible - "-android-cloexec-socket", // warning: 'pipe2' should use O_CLOEXEC where possible - ], -} - soong_config_module_type { name: "mgmt_cc_defaults", module_type: "cc_defaults", diff --git a/system/gd/README.md b/system/gd/README.md index 18a021132c..862bb3897c 100644 --- a/system/gd/README.md +++ b/system/gd/README.md @@ -7,7 +7,6 @@ Please see this [informative video we've prepared](https://www.youtube.com/watch Guidelines for developing the Gabeldorsche (GD) stack * [Architecture](./docs/architecture/architecture.md) -* [Style Guide](./docs/architecture/style_guide.md) ### Testing diff --git a/system/gd/common/audit_log.cc b/system/gd/common/audit_log.cc index 74be6f25c9..5897c70aac 100644 --- a/system/gd/common/audit_log.cc +++ b/system/gd/common/audit_log.cc @@ -16,9 +16,12 @@ #include "common/audit_log.h" +#ifdef __ANDROID__ +#include <log/log_event_list.h> +#endif // __ANDROID__ + #include "common/strings.h" #include "hci/hci_packets.h" -#include "os/log.h" namespace { #if defined(__ANDROID__) && !defined(FUZZ_TARGET) diff --git a/system/gd/common/byte_array_test.cc b/system/gd/common/byte_array_test.cc index 4798faccf0..b9a64b3882 100644 --- a/system/gd/common/byte_array_test.cc +++ b/system/gd/common/byte_array_test.cc @@ -18,8 +18,6 @@ #include <gtest/gtest.h> -#include "os/log.h" - using bluetooth::common::ByteArray; namespace { diff --git a/system/gd/common/circular_buffer_test.cc b/system/gd/common/circular_buffer_test.cc index 577bb6681b..e35a60c98e 100644 --- a/system/gd/common/circular_buffer_test.cc +++ b/system/gd/common/circular_buffer_test.cc @@ -22,8 +22,6 @@ #include <limits> #include <string> -#include "os/log.h" - namespace testing { long long timestamp_{0}; diff --git a/system/gd/common/lru_cache.h b/system/gd/common/lru_cache.h index 75b104f268..303688d55f 100644 --- a/system/gd/common/lru_cache.h +++ b/system/gd/common/lru_cache.h @@ -27,7 +27,6 @@ #include <unordered_map> #include "common/list_map.h" -#include "os/log.h" namespace bluetooth { namespace common { diff --git a/system/gd/common/metric_id_manager.cc b/system/gd/common/metric_id_manager.cc index 84268dba1d..131b09402c 100644 --- a/system/gd/common/metric_id_manager.cc +++ b/system/gd/common/metric_id_manager.cc @@ -27,8 +27,6 @@ #include <optional> #include <thread> -#include "os/log.h" - namespace bluetooth { namespace common { diff --git a/system/gd/common/strings.h b/system/gd/common/strings.h index ed5af390aa..5593715eb2 100644 --- a/system/gd/common/strings.h +++ b/system/gd/common/strings.h @@ -32,7 +32,6 @@ #include <vector> #include "common/type_helper.h" -#include "os/log.h" namespace bluetooth { namespace common { diff --git a/system/gd/common/sync_map_count_test.cc b/system/gd/common/sync_map_count_test.cc index 189e6f47c6..0e29c32467 100644 --- a/system/gd/common/sync_map_count_test.cc +++ b/system/gd/common/sync_map_count_test.cc @@ -23,8 +23,6 @@ #include <cstring> #include <vector> -#include "os/log.h" - namespace testing { const char* data[] = { diff --git a/system/gd/docs/architecture/style_guide.md b/system/gd/docs/architecture/style_guide.md deleted file mode 100644 index bdc5657f9a..0000000000 --- a/system/gd/docs/architecture/style_guide.md +++ /dev/null @@ -1,209 +0,0 @@ -# Gabeldorsche Style Guide - -[TOC] - -## Base - -In general, when not mentioned in this document, developers should follow the -Google C++ and Google Java style guide as much as possible. - -### Google C++ Style Guide - -C++ Style Guide: https://google.github.io/styleguide/cppguide.html - -### Android and Google Java Style Guide - -1. Android Java Style Guide: - https://source.android.com/setup/contribute/code-style - -2. when not covered by (1), see External Java Style Guide: - https://google.github.io/styleguide/javaguide.html - -line length limit is 120 characters for C++ and Java - -### Python Style Guide - -The GD stack uses the Google Python Style Guide: - -* http://google.github.io/styleguide/pyguide.html - -with the following modifications as shown in the -[.style.yapf](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/refs/heads/master/.style.yapf) definition: - -```yapf -based_on_style: google -indent_width: 4 -column_limit: 120 -``` - -## Build files - -* One build target for the entire stack in packages/modules/Bluetooth/system (i.e. one cc_library()) - * If only part of the stack needs to be compiled, configure it using the - “target” configuration in Android.bp -* One build target for all unit tests (i.e. one cc_test) -* When needed, filgroup() can be created in Android.bp in sub-directories. The - main build target should use these filegroups() to build the main output - library. -* All targets must have host_supported == true unless it is dependent on the - OS -* If the stack needs to be compiled using other build system, then the build - files should also live in packages/modules/Bluetooth/system - -## Namespace and include - -* Namespace must follow directory names -* Top level namespace for internal code is “bluetooth” -* Top level namespace for externally visible code is “android::bluetooth” -* Include path must be relative to the root directory of the stack. Normally - it is packages/modules/Bluetooth/system, for GD refactor code, it is packages/modules/Bluetooth/system/gd - -## Multiple implementations of the same header - -Since GD interact with many lower level components that are platform dependent, -frequently there is need to implement the same header multiple times for -different platform or hardware. When doing this: - -* Avoid #define macros as much as possible. Instead put code into different - source files and selectively compile them for different targets. -* Convention of operating system used: - * android/ - * All Android devices that use HIDL - * linux/ - * All non-Android linux devices - * linux_generic/ - * Android and non-Android linux devices - -## Directory structure - -Root directory under Android tree: -[**packages/modules/Bluetooth/system/gd/**](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/refs/heads/master/gd/) - -* Directory structure should be as flat as possible -* Each file should contain at most one class -* Header, source code, and unit test should live in the same directory with - the following naming guideline: - * Source: bb.cc - * Header: bb.h - * Test: bb_test.cc -* Each profile should have its own directory and module -* Source and sink, server and client profiles should live in two sub folders - of the same common directory where common code can be stored. However, - source and sink must have separate modules -* Module file is also the external API header -* Prefer underscore over dashes - -### Example: utility library with OS dependent implementation - -* os/: OS dependent classes such as Alarm, Thread, Handler - * Android.bp: Build file that defines file groups that would include - different source files based on compile time target - * alarm.h: common header for alarm - * linux_generic/: Implementations for generic Linux OS - * alarm.cc: Linux generic implementation of alarm.h using timer_fd - * alarm_test.cc: unit test for alarm.h - * fuzz/: library needed for fuzz tests in the os/ library - -### Example: module with hardware dependent implementation - -* hal/: Hardware abstraction layer such as HCI interfaces, Audio interfaces - * Android.bp: Build file that defines file groups that would include - different source files based on compile time target - * hci_hal.h: common library header - * hci_hal_android_hidl.cc: implementation of hci_hal.h using Android HIDL - * hci_hal_android_hidl_test.cc: unit tests for the Android HIDL - implementation - * hci_hal_host.cc: implementation of hci_hal.h using linux Bluetooth HCI - socket - * hci_hal_host_rootcanal.cc: implementation of hci_hal.h using root-canal - emulator - * hci_hal_host_test.cc: unit tests for the socket based HAL (root-canal) - emulator implementation - * facade.proto: gRPC automation interface definition for this layer - * facade.h/cc: an implementation of the above gRPC interface for the GD - stack - * cert/: certification tests for this module - * fuzz/: library needed for fuzz tests in the hal/ module - -### Example: similar protocol with the same base - -* l2cap/: L2CAP layer, splitted among classic and LE - * classic/: Classic L2CAP module - * cert/: certification tests for this module - * internal/: internal code to be used only in classic - * Source code and headers being exported to other modules - * le/: LE L2CAP module - * cert/: certification tests for this module - * internal/: internal code to be used only in classic - * Source code and headers being exported to other modules - * internal/: L2CAP internal code that should not be used by sources - outside L2CAP - * data_pipeline_manager.h - * data_pipeline_manager.cc - * data_pipeline_manager_mock.h: Mock of this class, used in unit tests - * dynamic_channel_allocator.h - * dynamic_channel_allocator.cc - * dynamic_channel_allocator_test.cc: GTest unit test of this class - * dynamic_channel_allocator_fuzz_test.cc: Fuzz test of this class - * *.h/.cc: Common headers and sources that is exposed to other modules - -### Example: protocol or profiles with client and server side implementations - -* a2dp/: A2DP profile - * sink/: A2DP sink module (e.g. headset) - * source/: A2DP source module (e.g. phone) -* avrcp/ - * controller/: AVRCP peripheral module (e.g. carkit) - * target/: AVRCP target module (e.g. Phone) -* hfp/ - * hf/: Handsfree device (e.g. headset) - * ag/: Audio gateway (e.g. phone) - -## External libraries - -To maintain high portability, we are trying to stick with C++ STL as much as -possible. Hence, before including an external library, please ask the team for -review. - -Examples of currently used libraries: - -* boringssl: Google's openssl implementation -* small parts of libchrome, to be removed or replaced eventually - * base::OnceCallback - * base::Callback - * base::BindOnce - * base::Bind -* google-breakpad: host binary crash handler -* libunwindstack: print stacktrace on crash on host - -## Exposed symbols - -Given that entire Fluoride library is held in libbluetooth.so dynamic library -file, we need a way to load this library and extract entry points to it. The -only symbols that should be exposed are: - -* An entry point to a normal running adapter module libbluetooth.so -* A header library to all exposed API service to profiles and layers -* An entry point to a certification interface, libbluetooth\_certification.so -* A header library to this certification stack - -## Logging - -Gabeldorsche uses `printf` style logging with macros defined in `os/log.h`. Five -log levels are available. - -* LOG_VERBOSE(fmt, args...): Will be disabled by default -* LOG_INFO(fmt, args...): Will be disabled by default -* LOG_INFO(fmt, args...): Enabled -* LOG_WARN(fmt, args...): Enabled -* LOG_ERROR(fmt, args...): Enabled -* LOG_ALWAYS_FATAL(fmt, args...): Enabled, will always crash -* ASSERT(condition): Enabled, will crash when condition is false -* ASSERT_LOG(conditon, fmt, args...): Enabled, will crash and print log when - condition is false - -In general, errors that are caused by remote device should never crash our stack -and should be logged using LOG_WARN() only. Recoverable errors due to our stack -or badly behaved bluetooth controller firmware should be logged using -LOG_ERROR() before recovery. Non-recoverable errors should be logged as -LOG_ALWAYS_FATAL() to crash the stack and restart. diff --git a/system/gd/docs/testing/gtest.md b/system/gd/docs/testing/gtest.md index 5120250a22..9ec38f8215 100644 --- a/system/gd/docs/testing/gtest.md +++ b/system/gd/docs/testing/gtest.md @@ -134,7 +134,6 @@ Note: All paths are relative to #include "l2cap/internal/channel_impl.h" #include "l2cap/l2cap_packets.h" #include "os/handler.h" -#include "os/log.h" namespace bluetooth { namespace l2cap { diff --git a/system/gd/dumpsys/Android.bp b/system/gd/dumpsys/Android.bp index 085c44b7f9..84074824ac 100644 --- a/system/gd/dumpsys/Android.bp +++ b/system/gd/dumpsys/Android.bp @@ -27,7 +27,6 @@ filegroup { genrule { name: "BluetoothGeneratedDumpsysTestData_h", - visibility: ["//visibility:public"], tools: [ "flatc", ], @@ -155,7 +154,6 @@ cc_library { name: "libbluetooth-dumpsys", host_supported: true, defaults: [ - "gd_clang_tidy", "gd_defaults", ], generated_sources: [ @@ -171,7 +169,6 @@ cc_library { name: "libbluetooth-dumpsys-test", host_supported: true, defaults: [ - "gd_clang_tidy", "gd_defaults", ], generated_sources: [ @@ -183,7 +180,6 @@ cc_library { name: "libbluetooth-dumpsys-unittest", host_supported: true, defaults: [ - "gd_clang_tidy", "gd_defaults", ], generated_headers: [ diff --git a/system/gd/dumpsys/internal/filter_internal.cc b/system/gd/dumpsys/internal/filter_internal.cc index a26c56383f..2db2878f95 100644 --- a/system/gd/dumpsys/internal/filter_internal.cc +++ b/system/gd/dumpsys/internal/filter_internal.cc @@ -23,7 +23,6 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" -#include "os/log.h" #define DBG 0 diff --git a/system/gd/dumpsys/internal/filter_internal_test.cc b/system/gd/dumpsys/internal/filter_internal_test.cc index 2db4b2d007..38f3481f0c 100644 --- a/system/gd/dumpsys/internal/filter_internal_test.cc +++ b/system/gd/dumpsys/internal/filter_internal_test.cc @@ -27,7 +27,6 @@ #include "dumpsys/internal/test_data/string_generated.h" #include "dumpsys/internal/test_data/struct_bfbs.h" #include "dumpsys/internal/test_data/struct_generated.h" -#include "os/log.h" namespace testing { diff --git a/system/gd/dumpsys/reflection_schema.cc b/system/gd/dumpsys/reflection_schema.cc index 3ab9fc2803..b2d79313eb 100644 --- a/system/gd/dumpsys/reflection_schema.cc +++ b/system/gd/dumpsys/reflection_schema.cc @@ -23,7 +23,6 @@ #include "bundler_schema_generated.h" #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" -#include "os/log.h" using namespace bluetooth; diff --git a/system/gd/facade/grpc_root_server.cc b/system/gd/facade/grpc_root_server.cc index 886e6d9b30..8e3bfb3f3f 100644 --- a/system/gd/facade/grpc_root_server.cc +++ b/system/gd/facade/grpc_root_server.cc @@ -30,7 +30,6 @@ #include "hci/facade/le_initiator_address_facade.h" #include "hci/facade/le_scanning_manager_facade.h" #include "neighbor/facade/facade.h" -#include "os/log.h" #include "os/thread.h" #include "stack_manager.h" diff --git a/system/gd/grpc/grpc_event_queue.h b/system/gd/grpc/grpc_event_queue.h index c181573ab1..c7f8c87314 100644 --- a/system/gd/grpc/grpc_event_queue.h +++ b/system/gd/grpc/grpc_event_queue.h @@ -25,7 +25,6 @@ #include "blueberry/facade/common.pb.h" #include "common/blocking_queue.h" -#include "os/log.h" namespace bluetooth { namespace grpc { diff --git a/system/gd/grpc/grpc_module.cc b/system/gd/grpc/grpc_module.cc index 93979f533e..53b40f8035 100644 --- a/system/gd/grpc/grpc_module.cc +++ b/system/gd/grpc/grpc_module.cc @@ -18,8 +18,6 @@ #include <bluetooth/log.h> -#include "os/log.h" - using ::grpc::Server; using ::grpc::ServerBuilder; diff --git a/system/gd/hal/hci_hal_host.cc b/system/gd/hal/hci_hal_host.cc index c6bba6968a..79e1cabd85 100644 --- a/system/gd/hal/hci_hal_host.cc +++ b/system/gd/hal/hci_hal_host.cc @@ -37,7 +37,6 @@ #include "hal/mgmt.h" #include "hal/snoop_logger.h" #include "metrics/counter_metrics.h" -#include "os/log.h" #include "os/reactor.h" #include "os/thread.h" diff --git a/system/gd/hal/hci_hal_host_rootcanal.cc b/system/gd/hal/hci_hal_host_rootcanal.cc index 26ffa84894..05d898228d 100644 --- a/system/gd/hal/hci_hal_host_rootcanal.cc +++ b/system/gd/hal/hci_hal_host_rootcanal.cc @@ -31,7 +31,6 @@ #include "hal/hci_hal_host.h" #include "hal/snoop_logger.h" #include "metrics/counter_metrics.h" -#include "os/log.h" #include "os/reactor.h" #include "os/thread.h" diff --git a/system/gd/hal/hci_hal_host_test.cc b/system/gd/hal/hci_hal_host_test.cc index 14c689738e..ab0ccef8f6 100644 --- a/system/gd/hal/hci_hal_host_test.cc +++ b/system/gd/hal/hci_hal_host_test.cc @@ -34,7 +34,6 @@ #include "hal/hci_hal.h" #include "hal/serialize_packet.h" -#include "os/log.h" #include "os/thread.h" #include "os/utils.h" #include "packet/raw_builder.h" diff --git a/system/gd/hal/mgmt.cc b/system/gd/hal/mgmt.cc index dd2e0bca6e..c5de32c3f7 100644 --- a/system/gd/hal/mgmt.cc +++ b/system/gd/hal/mgmt.cc @@ -30,8 +30,6 @@ #include <cerrno> -#include "os/log.h" - extern int GetAdapterIndex(); namespace bluetooth { diff --git a/system/gd/hal/ranging_hal_android.cc b/system/gd/hal/ranging_hal_android.cc index 658b7d777b..893a25fd10 100644 --- a/system/gd/hal/ranging_hal_android.cc +++ b/system/gd/hal/ranging_hal_android.cc @@ -23,7 +23,7 @@ #include <unordered_map> -// AIDL uses syslog.h, so these defines conflict with os/log.h +// AIDL uses syslog.h, so these defines conflict with log/log.h #undef LOG_DEBUG #undef LOG_INFO #undef LOG_WARNING diff --git a/system/gd/hal/ranging_hal_host.cc b/system/gd/hal/ranging_hal_host.cc index 16e44995b6..36c821f419 100644 --- a/system/gd/hal/ranging_hal_host.cc +++ b/system/gd/hal/ranging_hal_host.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -// AIDL uses syslog.h, so these defines conflict with os/log.h +// AIDL uses syslog.h, so these defines conflict with log/log.h #undef LOG_DEBUG #undef LOG_INFO #undef LOG_WARNING diff --git a/system/gd/hci/acl_manager/assembler.h b/system/gd/hci/acl_manager/assembler.h index 147cc7a99e..d126a980a2 100644 --- a/system/gd/hci/acl_manager/assembler.h +++ b/system/gd/hci/acl_manager/assembler.h @@ -26,7 +26,6 @@ #include "hci/acl_manager/acl_connection.h" #include "hci/address_with_type.h" #include "os/handler.h" -#include "os/log.h" #include "packet/packet_view.h" namespace bluetooth { 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 8cc66ab807..97ee9fc4af 100644 --- a/system/gd/hci/acl_manager/classic_acl_connection_test.cc +++ b/system/gd/hci/acl_manager/classic_acl_connection_test.cc @@ -33,7 +33,6 @@ #include "hci/address.h" #include "hci/hci_packets.h" #include "os/handler.h" -#include "os/log.h" #include "os/thread.h" using namespace bluetooth; diff --git a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc index 210cc71125..f019bf8fe1 100644 --- a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc +++ b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc @@ -23,7 +23,6 @@ #include "hci/controller.h" #include "hci/hci_packets.h" #include "os/handler.h" -#include "os/log.h" #include "packet/raw_builder.h" using ::bluetooth::common::BidiQueue; diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc index d448de6264..b5d84af804 100644 --- a/system/gd/hci/distance_measurement_manager.cc +++ b/system/gd/hci/distance_measurement_manager.cc @@ -32,7 +32,6 @@ #include "hci/hci_layer.h" #include "module.h" #include "os/handler.h" -#include "os/log.h" #include "os/repeating_alarm.h" #include "packet/packet_view.h" #include "ras/ras_packets.h" @@ -63,14 +62,13 @@ 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 uint8_t kToneAntennaConfigSelection = 0x00; // 1x1 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 uint16_t kDefaultIntervalMs = 1000; // 1s -static constexpr uint8_t kPreferredPeerAntennaValue = 0x01; // Use first ordered antenna element +static constexpr uint8_t kMaxRetryCounterForCreateConfig = 0x03; struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { struct CsProcedureData { @@ -143,21 +141,37 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { std::unique_ptr<os::RepeatingAlarm> repeating_alarm; }; + // TODO: use state machine to manage the tracker. + enum class CsTrackerState : uint8_t { + UNSPECIFIED = 0x00, + STOPPED = 1 << 0, + INIT = 1 << 1, + RAS_CONNECTED = 1 << 2, + WAIT_FOR_CONFIG_COMPLETE = 1 << 3, + WAIT_FOR_SECURITY_ENABLED = 1 << 4, + WAIT_FOR_PROCEDURE_ENABLED = 1 << 5, + STARTED = 1 << 6, + }; + struct CsTracker { + CsTrackerState state = CsTrackerState::STOPPED; Address address; hci::Role local_hci_role = hci::Role::CENTRAL; uint16_t procedure_counter = 0; CsRole role = CsRole::INITIATOR; bool local_start = false; // If the CS was started by the local device. + // TODO: clean up, replace the measurement_ongoing with STOPPED bool measurement_ongoing = false; bool ras_connected = false; bool setup_complete = false; bool config_set = false; + uint8_t retry_counter_for_create_config = 0; uint16_t n_procedure_count = 0; CsMainModeType main_mode_type = CsMainModeType::MODE_2; CsSubModeType sub_mode_type = CsSubModeType::UNUSED; CsRttType rtt_type = CsRttType::RTT_AA_ONLY; bool remote_support_phase_based_ranging = false; + uint8_t remote_num_antennas_supported_ = 0x01; uint8_t config_id = kInvalidConfigId; uint8_t selected_tx_power = 0; std::vector<CsProcedureData> procedure_data_list = {}; @@ -316,6 +330,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (it->second.repeating_alarm == nullptr) { it->second.repeating_alarm = std::make_unique<os::RepeatingAlarm>(handler_); } + it->second.state = CsTrackerState::INIT; it->second.interval_ms = interval; it->second.local_start = true; it->second.measurement_ongoing = true; @@ -383,8 +398,9 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { log::warn("Can't find CS tracker for {}", address); } else if (it->second.measurement_ongoing) { it->second.repeating_alarm->Cancel(); - reset_tracker_on_stopped(it->second); send_le_cs_procedure_enable(connection_handle, Enable::DISABLED); + // does not depend on the 'disable' command result. + reset_tracker_on_stopped(it->second); } } break; } @@ -408,6 +424,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { return; } it->second.ras_connected = true; + it->second.state = CsTrackerState::RAS_CONNECTED; if (ranging_hal_->IsBound()) { ranging_hal_->OpenSession(connection_handle, att_handle, vendor_specific_data); @@ -466,6 +483,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { cs_responder_trackers_[connection_handle] = CsTracker(); it = cs_responder_trackers_.find(connection_handle); } + it->second.state = CsTrackerState::RAS_CONNECTED; it->second.address = identity_address; it->second.local_start = false; it->second.local_hci_role = local_hci_role; @@ -568,6 +586,10 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { } 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); + } + 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)); @@ -582,6 +604,10 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { } void send_le_cs_create_config(uint16_t connection_handle, uint8_t config_id) { + if (cs_requester_trackers_.find(connection_handle) == cs_requester_trackers_.end()) { + log::warn("no cs tracker found for {}", connection_handle); + } + cs_requester_trackers_[connection_handle].state = CsTrackerState::WAIT_FOR_CONFIG_COMPLETE; auto channel_vector = common::FromHexString("1FFFFFFFFFFFFC7FFFFC"); // use all 72 Channel std::array<uint8_t, 10> channel_map; std::copy(channel_vector->begin(), channel_vector->end(), channel_map.begin()); @@ -591,32 +617,44 @@ 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_ONLY, CsSyncPhy::LE_1M_PHY, channel_map, + CsConfigRttType::RTT_AA_COARSE, 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)); } - void send_le_cs_set_procedure_parameters(uint16_t connection_handle, uint8_t config_id) { + void send_le_cs_set_procedure_parameters(uint16_t connection_handle, uint8_t config_id, + uint8_t remote_num_antennas_supported) { + uint8_t tone_antenna_config_selection = + cs_tone_antenna_config_mapping_table_[num_antennas_supported_ - 1] + [remote_num_antennas_supported - 1]; + uint8_t preferred_peer_antenna_value = + cs_preferred_peer_antenna_mapping_table_[tone_antenna_config_selection]; + log::info( + "num_antennas_supported:{}, remote_num_antennas_supported:{}, " + "tone_antenna_config_selection:{}, preferred_peer_antenna:{}", + num_antennas_supported_, remote_num_antennas_supported, tone_antenna_config_selection, + preferred_peer_antenna_value); CsPreferredPeerAntenna preferred_peer_antenna; - preferred_peer_antenna.use_first_ordered_antenna_element_ = kPreferredPeerAntennaValue & 0x01; + preferred_peer_antenna.use_first_ordered_antenna_element_ = preferred_peer_antenna_value & 0x01; preferred_peer_antenna.use_second_ordered_antenna_element_ = - (kPreferredPeerAntennaValue >> 1) & 0x01; + (preferred_peer_antenna_value >> 1) & 0x01; preferred_peer_antenna.use_third_ordered_antenna_element_ = - (kPreferredPeerAntennaValue >> 2) & 0x01; + (preferred_peer_antenna_value >> 2) & 0x01; preferred_peer_antenna.use_fourth_ordered_antenna_element_ = - (kPreferredPeerAntennaValue >> 3) & 0x01; + (preferred_peer_antenna_value >> 3) & 0x01; hci_layer_->EnqueueCommand( LeCsSetProcedureParametersBuilder::Create( connection_handle, config_id, kMaxProcedureLen, kMinProcedureInterval, kMaxProcedureInterval, kMaxProcedureCount, kMinSubeventLen, kMaxSubeventLen, - kToneAntennaConfigSelection, CsPhy::LE_1M_PHY, kTxPwrDelta, + tone_antenna_config_selection, CsPhy::LE_1M_PHY, kTxPwrDelta, preferred_peer_antenna, CsSnrControl::NOT_APPLIED, CsSnrControl::NOT_APPLIED), handler_->BindOnceOn(this, &impl::on_cs_set_procedure_parameters)); } static void reset_tracker_on_stopped(CsTracker& cs_tracker) { cs_tracker.measurement_ongoing = false; + cs_tracker.state = CsTrackerState::STOPPED; } void handle_cs_setup_failure(uint16_t connection_handle, DistanceMeasurementErrorCode errorCode) { @@ -644,12 +682,21 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { return; } - if (!it->second.measurement_ongoing) { - log::error("safe guard, error state, no local measurement request."); - if (it->second.repeating_alarm) { - it->second.repeating_alarm->Cancel(); + if (enable == Enable::ENABLED) { + if (it->second.state == CsTrackerState::STOPPED) { + log::error("safe guard, error state, no local measurement request."); + if (it->second.repeating_alarm) { + it->second.repeating_alarm->Cancel(); + } + return; + } + it->second.state = CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED; + } else { // Enable::DISABLE + if (it->second.state != CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED && + it->second.state != CsTrackerState::STARTED) { + log::info("no procedure disable command needed for state {}.", (int)it->second.state); + return; } - return; } hci_layer_->EnqueueCommand( @@ -694,6 +741,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { return; } cs_subfeature_supported_ = complete_view.GetOptionalSubfeaturesSupported(); + num_antennas_supported_ = complete_view.GetNumAntennasSupported(); } void on_cs_read_remote_supported_capabilities_complete( @@ -721,9 +769,11 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (req_it != cs_requester_trackers_.end() && req_it->second.measurement_ongoing) { req_it->second.remote_support_phase_based_ranging = event_view.GetOptionalSubfeaturesSupported().phase_based_ranging_ == 0x01; + req_it->second.remote_num_antennas_supported_ = event_view.GetNumAntennasSupported(); req_it->second.setup_complete = true; log::info("Setup phase complete, connection_handle: {}, address: {}", connection_handle, cs_requester_trackers_[connection_handle].address); + req_it->second.retry_counter_for_create_config = 0; send_le_cs_create_config(connection_handle, cs_requester_trackers_[connection_handle].config_id); } @@ -762,11 +812,18 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); return; } - auto it = cs_requester_trackers_.find(connection_handle); - if (it != cs_requester_trackers_.end() && it->second.measurement_ongoing && - !it->second.config_set) { - it->second.config_set = true; - send_le_cs_set_procedure_parameters(event_view.GetConnectionHandle(), it->second.config_id); + auto req_it = cs_requester_trackers_.find(connection_handle); + if (req_it != cs_requester_trackers_.end() && req_it->second.measurement_ongoing && + !req_it->second.config_set) { + req_it->second.config_set = true; + send_le_cs_set_procedure_parameters(event_view.GetConnectionHandle(), + req_it->second.config_id, + req_it->second.remote_num_antennas_supported_); + } + auto res_it = cs_responder_trackers_.find(connection_handle); + if (res_it != cs_responder_trackers_.end() && + res_it->second.state == CsTrackerState::WAIT_FOR_SECURITY_ENABLED) { + res_it->second.state = CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED; } } @@ -779,11 +836,31 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (event_view.GetStatus() != ErrorCode::SUCCESS) { std::string error_code = ErrorCodeText(event_view.GetStatus()); log::warn("Received LeCsConfigCompleteView with error code {}", error_code); - handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + // The Create Config LL packet may arrive before the remote side has finished setting default + // settings, which will result in create config failure. Retry to ensure the remote side has + // completed its setup. + if (cs_requester_trackers_.find(connection_handle) != cs_requester_trackers_.end() && + cs_requester_trackers_[connection_handle].retry_counter_for_create_config < + kMaxRetryCounterForCreateConfig) { + cs_requester_trackers_[connection_handle].retry_counter_for_create_config++; + log::info("send_le_cs_create_config, retry counter {}", + cs_requester_trackers_[connection_handle].retry_counter_for_create_config); + send_le_cs_create_config(connection_handle, + cs_requester_trackers_[connection_handle].config_id); + } else { + handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } return; } uint8_t config_id = event_view.GetConfigId(); - CsTracker* live_tracker = get_live_tracker(connection_handle, config_id); + check_and_handle_conflict(connection_handle, config_id, + CsTrackerState::WAIT_FOR_CONFIG_COMPLETE); + uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::WAIT_FOR_CONFIG_COMPLETE); + // any state, as the remote can start over at any time. + uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::UNSPECIFIED); + + CsTracker* live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, + valid_responder_states); if (live_tracker == nullptr) { log::warn("Can't find cs tracker for connection_handle {}", connection_handle); return; @@ -802,6 +879,10 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { // 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) { + live_tracker->state = CsTrackerState::WAIT_FOR_SECURITY_ENABLED; + } } void on_cs_set_procedure_parameters(CommandCompleteView view) { @@ -834,24 +915,53 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { } } - CsTracker* get_live_tracker(uint16_t connection_handle, uint8_t config_id) { - // suppose the config_id is unique, otherwise, no way to know if the event from controller - // is from local(requester) or remote(responder). + CsTracker* get_live_tracker(uint16_t connection_handle, uint8_t config_id, + uint8_t valid_requester_states, uint8_t valid_responder_states) { // CAVEAT: if the remote is sending request with the same config id, the behavior is undefined. - auto it = cs_requester_trackers_.find(connection_handle); - if (it != cs_requester_trackers_.end() && it->second.measurement_ongoing && - it->second.config_id == config_id) { - return &(it->second); + auto req_it = cs_requester_trackers_.find(connection_handle); + if (req_it != cs_requester_trackers_.end() && req_it->second.state != CsTrackerState::STOPPED && + req_it->second.config_id == config_id && + (valid_requester_states & static_cast<uint8_t>(req_it->second.state)) != 0) { + return &cs_requester_trackers_[connection_handle]; } - // take it as responder any way - if (cs_responder_trackers_.find(connection_handle) != cs_responder_trackers_.end()) { + + auto res_it = cs_responder_trackers_.find(connection_handle); + if (res_it != cs_responder_trackers_.end() && + (res_it->second.config_id == kInvalidConfigId || res_it->second.config_id == config_id) && + (valid_responder_states == static_cast<uint8_t>(CsTrackerState::UNSPECIFIED) || + (valid_responder_states & static_cast<uint8_t>(res_it->second.state)) != 0)) { return &cs_responder_trackers_[connection_handle]; } - - log::error("no event is expected as no any live cs tracker for {}", connection_handle); + log::error("no valid tracker to handle the event."); return nullptr; } + void check_and_handle_conflict(uint16_t connection_handle, uint8_t event_config_id, + CsTrackerState expected_requester_state) { + // If the local and remote were triggering the event at the same time, and the controller + // allows that happen, the things may still get messed; If the spec can differentiate the + // local event or remote event, that would be clearer. + auto it = cs_requester_trackers_.find(connection_handle); + if (it == cs_requester_trackers_.end()) { + return; + } + if (event_config_id != it->second.config_id) { + return; + } + if (it->second.state == expected_requester_state) { + return; + } + log::warn("unexpected request from remote, which is conflict with the local measurement."); + it->second.config_set = false; + if (it->second.state != CsTrackerState::STOPPED) { + stop_distance_measurement(it->second.address, connection_handle, + DistanceMeasurementMethod::METHOD_CS); + // TODO: clean up the stopped callback, it should be called within stop_distance_measurement. + distance_measurement_callbacks_->OnDistanceMeasurementStopped( + it->second.address, REASON_REMOTE_REQUEST, METHOD_CS); + } + } + void on_cs_procedure_enable_complete(LeCsProcedureEnableCompleteView event_view) { log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()"); uint16_t connection_handle = event_view.GetConnectionHandle(); @@ -863,13 +973,26 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { return; } uint8_t config_id = event_view.GetConfigId(); - CsTracker* live_tracker = get_live_tracker(connection_handle, config_id); - if (live_tracker == nullptr) { - log::error("no tracker is available for {}", connection_handle); - return; - } + + CsTracker* live_tracker = nullptr; if (event_view.GetState() == Enable::ENABLED) { + check_and_handle_conflict(connection_handle, config_id, + CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED); + uint8_t valid_requester_states = + static_cast<uint8_t>(CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED); + uint8_t valid_responder_states = + static_cast<uint8_t>(CsTrackerState::STOPPED) | + static_cast<uint8_t>(CsTrackerState::INIT) | + static_cast<uint8_t>(CsTrackerState::STARTED) | + static_cast<uint8_t>(CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED); + live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, + valid_responder_states); + if (live_tracker == nullptr) { + log::error("no tracker is available for {}", connection_handle); + return; + } log::debug("Procedure enabled, {}", event_view.ToString()); + live_tracker->state = CsTrackerState::STARTED; // assign the config_id, as this is may be the 1st time to get it for responder; live_tracker->config_id = config_id; live_tracker->selected_tx_power = event_view.GetSelectedTxPower(); @@ -880,15 +1003,15 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { distance_measurement_callbacks_->OnDistanceMeasurementStarted(live_tracker->address, METHOD_CS); } - // cs role switch from requester to responder, may reset the config if conflict. - if (!live_tracker->local_start && - cs_requester_trackers_.find(connection_handle) != cs_requester_trackers_.end() && - cs_requester_trackers_[connection_handle].config_id == live_tracker->config_id) { - log::debug("config id {} from remote is the same as the cached local, reset config_set.", - cs_requester_trackers_[connection_handle].config_id); - cs_requester_trackers_[connection_handle].config_set = false; - } } else if (event_view.GetState() == Enable::DISABLED) { + uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED); + uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::STARTED); + live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, + valid_responder_states); + if (live_tracker == nullptr) { + log::error("no tracker is available for {}", connection_handle); + return; + } reset_tracker_on_stopped(*live_tracker); } // reset the procedure data list. @@ -912,6 +1035,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { SubeventAbortReason subevent_abort_reason; std::vector<LeCsResultDataStructure> result_data_structures; CsTracker* live_tracker = nullptr; + uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED); + 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); if (!cs_event_result.IsValid()) { @@ -919,7 +1044,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { return; } connection_handle = cs_event_result.GetConnectionHandle(); - live_tracker = get_live_tracker(connection_handle, cs_event_result.GetConfigId()); + live_tracker = get_live_tracker(connection_handle, cs_event_result.GetConfigId(), + valid_requester_states, valid_responder_states); if (live_tracker == nullptr) { log::error("no live tracker is available for {}", connection_handle); return; @@ -951,7 +1077,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { return; } connection_handle = cs_event_result.GetConnectionHandle(); - live_tracker = get_live_tracker(connection_handle, cs_event_result.GetConfigId()); + live_tracker = get_live_tracker(connection_handle, cs_event_result.GetConfigId(), + valid_requester_states, valid_responder_states); procedure_done_status = cs_event_result.GetProcedureDoneStatus(); subevent_done_status = cs_event_result.GetSubeventDoneStatus(); procedure_abort_reason = cs_event_result.GetProcedureAbortReason(); @@ -1074,6 +1201,10 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { log::warn("can't find tracker for 0x{:04x}", connection_handle); return; } + if (cs_requester_trackers_[connection_handle].state != CsTrackerState::STARTED) { + log::warn("The measurement for {} is stopped, ignore the remote data.", connection_handle); + return; + } auto& tracker = cs_requester_trackers_[connection_handle]; SegmentationHeader segmentation_header; @@ -1648,6 +1779,13 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { std::unordered_map<uint16_t, CsTracker> cs_responder_trackers_; DistanceMeasurementCallbacks* distance_measurement_callbacks_; CsOptionalSubfeaturesSupported cs_subfeature_supported_; + uint8_t num_antennas_supported_ = 0x01; + // A table that maps num_antennas_supported and remote_num_antennas_supported to Antenna + // Configuration Index. + uint8_t cs_tone_antenna_config_mapping_table_[4][4] = { + {0, 4, 5, 6}, {1, 7, 7, 7}, {2, 7, 7, 7}, {3, 7, 7, 7}}; + // A table that maps Antenna Configuration Index to Preferred Peer Antenna. + uint8_t cs_preferred_peer_antenna_mapping_table_[8] = {1, 1, 1, 1, 3, 7, 15, 3}; // Antenna path permutations. See Channel Sounding CR_PR for the details. uint8_t cs_antenna_permutation_array_[24][4] = { {1, 2, 3, 4}, {2, 1, 3, 4}, {1, 3, 2, 4}, {3, 1, 2, 4}, {3, 2, 1, 4}, {2, 3, 1, 4}, diff --git a/system/gd/hci/event_checkers.h b/system/gd/hci/event_checkers.h index 41aca0718f..a484f5752e 100644 --- a/system/gd/hci/event_checkers.h +++ b/system/gd/hci/event_checkers.h @@ -19,7 +19,6 @@ #include <bluetooth/log.h> #include "hci/hci_packets.h" -#include "os/log.h" namespace bluetooth { namespace hci { diff --git a/system/gd/hci/facade/le_advertising_manager_facade.cc b/system/gd/hci/facade/le_advertising_manager_facade.cc index 43b68aedf5..d9c6cca0d8 100644 --- a/system/gd/hci/facade/le_advertising_manager_facade.cc +++ b/system/gd/hci/facade/le_advertising_manager_facade.cc @@ -31,7 +31,6 @@ #include "hci/address.h" #include "hci/address_with_type.h" #include "hci/le_advertising_manager.h" -#include "os/log.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/gd/hci/facade/le_scanning_manager_facade.cc b/system/gd/hci/facade/le_scanning_manager_facade.cc index 8a2e7f90ee..243b46ff4e 100644 --- a/system/gd/hci/facade/le_scanning_manager_facade.cc +++ b/system/gd/hci/facade/le_scanning_manager_facade.cc @@ -28,7 +28,6 @@ #include "common/bind.h" #include "grpc/grpc_event_queue.h" #include "hci/le_scanning_manager.h" -#include "os/log.h" #include "packet/raw_builder.h" namespace bluetooth { diff --git a/system/gd/hci/fuzz/acl_manager_fuzz_test.cc b/system/gd/hci/fuzz/acl_manager_fuzz_test.cc index 527982ced5..06544789b7 100644 --- a/system/gd/hci/fuzz/acl_manager_fuzz_test.cc +++ b/system/gd/hci/fuzz/acl_manager_fuzz_test.cc @@ -24,7 +24,6 @@ #include "hci/hci_layer.h" #include "module.h" #include "os/fake_timer/fake_timerfd.h" -#include "os/log.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/gd/hci/fuzz/fuzz_hci_layer.h b/system/gd/hci/fuzz/fuzz_hci_layer.h index 07a58fdc74..10492cdda9 100644 --- a/system/gd/hci/fuzz/fuzz_hci_layer.h +++ b/system/gd/hci/fuzz/fuzz_hci_layer.h @@ -26,7 +26,6 @@ #include "hci/hci_layer.h" #include "os/fuzz/dev_null_queue.h" #include "os/fuzz/fuzz_inject_queue.h" -#include "os/log.h" namespace bluetooth { namespace hci { diff --git a/system/gd/hci/fuzz/hci_layer_fuzz_test.cc b/system/gd/hci/fuzz/hci_layer_fuzz_test.cc index 48191efe1c..392ffdd3e6 100644 --- a/system/gd/hci/fuzz/hci_layer_fuzz_test.cc +++ b/system/gd/hci/fuzz/hci_layer_fuzz_test.cc @@ -24,7 +24,6 @@ #include "hci/hci_layer.h" #include "module.h" #include "os/fake_timer/fake_timerfd.h" -#include "os/log.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/gd/hci/hci_layer.cc b/system/gd/hci/hci_layer.cc index 70a5f43b56..f9847101c0 100644 --- a/system/gd/hci/hci_layer.cc +++ b/system/gd/hci/hci_layer.cc @@ -279,6 +279,17 @@ struct HciLayer::impl { command_queue_.clear(); command_credits_ = 1; waiting_command_ = OpCode::NONE; + +#ifdef TARGET_FLOSS + log::warn("Ignoring the timeouted HCI command {}.", OpCodeText(op_code)); + // Terminate the process to trigger controller reset, also mark the controller + // is broken to prevent further error while terminating. + auto hal = module_.GetDependency<hal::HciHal>(); + hal->markControllerBroken(); + kill(getpid(), SIGTERM); + return; +#endif + // Ignore the response, since we don't know what might come back. enqueue_command(ControllerDebugInfoBuilder::Create(), module_.GetHandler()->BindOnce([](CommandCompleteView) {})); diff --git a/system/gd/hci/hci_layer_test.cc b/system/gd/hci/hci_layer_test.cc index 9f8d9ead3c..1f677d518b 100644 --- a/system/gd/hci/hci_layer_test.cc +++ b/system/gd/hci/hci_layer_test.cc @@ -24,7 +24,6 @@ #include "hal/hci_hal_fake.h" #include "hci/hci_packets.h" #include "module.h" -#include "os/log.h" #include "os/thread.h" #include "packet/bit_inserter.h" #include "packet/raw_builder.h" diff --git a/system/gd/hci/hci_packets_fuzz_test.cc b/system/gd/hci/hci_packets_fuzz_test.cc index 68ebf7e6da..2868477c46 100644 --- a/system/gd/hci/hci_packets_fuzz_test.cc +++ b/system/gd/hci/hci_packets_fuzz_test.cc @@ -18,7 +18,6 @@ #include <memory> #include "hci/hci_packets.h" -#include "os/log.h" #include "packet/bit_inserter.h" #include "packet/raw_builder.h" diff --git a/system/gd/hci/hci_packets_test.cc b/system/gd/hci/hci_packets_test.cc index 9df54187bb..01121c7922 100644 --- a/system/gd/hci/hci_packets_test.cc +++ b/system/gd/hci/hci_packets_test.cc @@ -20,7 +20,6 @@ #define PACKET_TESTING // Instantiate the tests in the packet files #include "hci/hci_packets.h" -#include "os/log.h" #include "packet/bit_inserter.h" #include "packet/raw_builder.h" diff --git a/system/gd/hci/le_scanning_manager.cc b/system/gd/hci/le_scanning_manager.cc index 4ade641f93..6c9e9744b4 100644 --- a/system/gd/hci/le_scanning_manager.cc +++ b/system/gd/hci/le_scanning_manager.cc @@ -31,7 +31,6 @@ #include "hci/le_scanning_reassembler.h" #include "module.h" #include "os/handler.h" -#include "os/log.h" #include "os/system_properties.h" #include "storage/storage_module.h" diff --git a/system/gd/hci/le_scanning_reassembler.cc b/system/gd/hci/le_scanning_reassembler.cc index c3199221a3..8f8ad06b00 100644 --- a/system/gd/hci/le_scanning_reassembler.cc +++ b/system/gd/hci/le_scanning_reassembler.cc @@ -28,7 +28,6 @@ #include "hci/le_scanning_interface.h" #include "module.h" #include "os/handler.h" -#include "os/log.h" #include "storage/storage_module.h" namespace bluetooth::hci { diff --git a/system/gd/metrics/chromeos/metrics.cc b/system/gd/metrics/chromeos/metrics.cc index fbe7afcba3..9a7541735a 100644 --- a/system/gd/metrics/chromeos/metrics.cc +++ b/system/gd/metrics/chromeos/metrics.cc @@ -24,7 +24,6 @@ #include "metrics/chromeos/metrics_allowlist.h" #include "metrics/chromeos/metrics_event.h" #include "metrics/utils.h" -#include "os/log.h" namespace bluetooth { namespace metrics { diff --git a/system/gd/metrics/counter_metrics.cc b/system/gd/metrics/counter_metrics.cc index 0155eb1bd0..1315a87df1 100644 --- a/system/gd/metrics/counter_metrics.cc +++ b/system/gd/metrics/counter_metrics.cc @@ -20,7 +20,6 @@ #include <bluetooth/log.h> #include "common/bind.h" -#include "os/log.h" #include "os/metrics.h" namespace bluetooth { diff --git a/system/gd/module.h b/system/gd/module.h index 14c81ccaf4..44aa0bcb29 100644 --- a/system/gd/module.h +++ b/system/gd/module.h @@ -30,7 +30,6 @@ #include "common/bind.h" #include "os/handler.h" -#include "os/log.h" #include "os/thread.h" namespace bluetooth { diff --git a/system/gd/neighbor/name_db.cc b/system/gd/neighbor/name_db.cc index 99eca8d0e1..48cdae4705 100644 --- a/system/gd/neighbor/name_db.cc +++ b/system/gd/neighbor/name_db.cc @@ -28,7 +28,6 @@ #include "hci/remote_name_request.h" #include "module.h" #include "os/handler.h" -#include "os/log.h" namespace bluetooth { namespace neighbor { diff --git a/system/gd/neighbor/scan.cc b/system/gd/neighbor/scan.cc index fafb316b33..8559f338da 100644 --- a/system/gd/neighbor/scan.cc +++ b/system/gd/neighbor/scan.cc @@ -25,7 +25,6 @@ #include "hci/hci_packets.h" #include "module.h" #include "os/handler.h" -#include "os/log.h" namespace bluetooth { namespace neighbor { diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc index daea83d0a5..0a2dbd92b6 100644 --- a/system/gd/os/android/metrics.cc +++ b/system/gd/os/android/metrics.cc @@ -30,7 +30,6 @@ #include "common/strings.h" #include "hardware/bt_av.h" #include "hci/hci_packets.h" -#include "os/log.h" namespace fmt { template <> diff --git a/system/gd/os/android/system_properties.cc b/system/gd/os/android/system_properties.cc index d7dc9e918a..d0f2707173 100644 --- a/system/gd/os/android/system_properties.cc +++ b/system/gd/os/android/system_properties.cc @@ -23,7 +23,6 @@ #include <cctype> #include "common/strings.h" -#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/android/wakelock_native.cc b/system/gd/os/android/wakelock_native.cc index d34fa94cab..bc7d2ae130 100644 --- a/system/gd/os/android/wakelock_native.cc +++ b/system/gd/os/android/wakelock_native.cc @@ -32,20 +32,6 @@ #include <functional> #include <string> -// We want the os/log.h definitions -#undef LOG_DEBUG -#undef LOG_INFO - -#include "os/log.h" - -// Save the os/log.h definitions -#pragma push_macro("LOG_DEBUG") -#pragma push_macro("LOG_INFO") - -// Undef these to avoid conflicting with later imports -#undef LOG_DEBUG -#undef LOG_INFO - using ::aidl::android::system::suspend::ISystemSuspend; using ::aidl::android::system::suspend::IWakeLock; using ::aidl::android::system::suspend::WakeLockType; @@ -54,10 +40,6 @@ namespace bluetooth { namespace os { namespace internal { -// Restore the os/log.h definitions after all imported headers -#pragma pop_macro("LOG_DEBUG") -#pragma pop_macro("LOG_INFO") - static void onSuspendDeath(void* cookie) { auto onDeath = static_cast<std::function<void(void)>*>(cookie); (*onDeath)(); diff --git a/system/gd/os/chromeos/metrics.cc b/system/gd/os/chromeos/metrics.cc index 2ec46c8c55..b3795341f2 100644 --- a/system/gd/os/chromeos/metrics.cc +++ b/system/gd/os/chromeos/metrics.cc @@ -22,7 +22,6 @@ #include <metrics/structured_events.h> #include "metrics/utils.h" -#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/chromeos/parameter_provider.cc b/system/gd/os/chromeos/parameter_provider.cc index 2302a68e11..a8ee19c5a6 100644 --- a/system/gd/os/chromeos/parameter_provider.cc +++ b/system/gd/os/chromeos/parameter_provider.cc @@ -22,8 +22,6 @@ #include <mutex> #include <string> -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/os/chromeos/wakelock_native.cc b/system/gd/os/chromeos/wakelock_native.cc index 8cf7f71fde..33c84d45b5 100644 --- a/system/gd/os/chromeos/wakelock_native.cc +++ b/system/gd/os/chromeos/wakelock_native.cc @@ -22,8 +22,6 @@ #include <bluetooth/log.h> -#include "os/log.h" - namespace bluetooth { namespace os { namespace internal { diff --git a/system/gd/os/handler.cc b/system/gd/os/handler.cc index f49236fde3..388fcd4c72 100644 --- a/system/gd/os/handler.cc +++ b/system/gd/os/handler.cc @@ -20,7 +20,6 @@ #include "common/bind.h" #include "common/callback.h" -#include "os/log.h" #include "os/reactor.h" namespace bluetooth { diff --git a/system/gd/os/handler_unittest.cc b/system/gd/os/handler_unittest.cc index 0a06699c39..7306effd30 100644 --- a/system/gd/os/handler_unittest.cc +++ b/system/gd/os/handler_unittest.cc @@ -22,7 +22,6 @@ #include "common/bind.h" #include "common/callback.h" #include "gtest/gtest.h" -#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/host/metrics.cc b/system/gd/os/host/metrics.cc index 27e5d7d470..a019033348 100644 --- a/system/gd/os/host/metrics.cc +++ b/system/gd/os/host/metrics.cc @@ -18,8 +18,6 @@ #include "os/metrics.h" -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/os/host/parameter_provider.cc b/system/gd/os/host/parameter_provider.cc index 37d6232ebe..7b150da4be 100644 --- a/system/gd/os/host/parameter_provider.cc +++ b/system/gd/os/host/parameter_provider.cc @@ -23,8 +23,6 @@ #include <mutex> #include <string> -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/os/host/wakelock_native.cc b/system/gd/os/host/wakelock_native.cc index d09d91fbf3..dd8026d007 100644 --- a/system/gd/os/host/wakelock_native.cc +++ b/system/gd/os/host/wakelock_native.cc @@ -22,8 +22,6 @@ #include <bluetooth/log.h> -#include "os/log.h" - namespace bluetooth { namespace os { namespace internal { diff --git a/system/gd/os/linux/metrics.cc b/system/gd/os/linux/metrics.cc index df3a413eee..c5e38493da 100644 --- a/system/gd/os/linux/metrics.cc +++ b/system/gd/os/linux/metrics.cc @@ -18,8 +18,6 @@ #include "os/metrics.h" -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/os/linux/parameter_provider.cc b/system/gd/os/linux/parameter_provider.cc index 2302a68e11..a8ee19c5a6 100644 --- a/system/gd/os/linux/parameter_provider.cc +++ b/system/gd/os/linux/parameter_provider.cc @@ -22,8 +22,6 @@ #include <mutex> #include <string> -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/os/linux/wakelock_native.cc b/system/gd/os/linux/wakelock_native.cc index 8cf7f71fde..33c84d45b5 100644 --- a/system/gd/os/linux/wakelock_native.cc +++ b/system/gd/os/linux/wakelock_native.cc @@ -22,8 +22,6 @@ #include <bluetooth/log.h> -#include "os/log.h" - namespace bluetooth { namespace os { namespace internal { diff --git a/system/gd/os/linux_generic/alarm.cc b/system/gd/os/linux_generic/alarm.cc index 971b595dbc..46c06e5d26 100644 --- a/system/gd/os/linux_generic/alarm.cc +++ b/system/gd/os/linux_generic/alarm.cc @@ -25,7 +25,6 @@ #include "common/bind.h" #include "os/linux_generic/linux.h" -#include "os/log.h" #include "os/utils.h" #ifdef __ANDROID__ diff --git a/system/gd/os/linux_generic/files.cc b/system/gd/os/linux_generic/files.cc index 38896cccc7..a759e1d631 100644 --- a/system/gd/os/linux_generic/files.cc +++ b/system/gd/os/linux_generic/files.cc @@ -28,8 +28,6 @@ #include <streambuf> #include <string> -#include "os/log.h" - namespace { void HandleError(const std::string& temp_path, int* dir_fd, FILE** fp) { diff --git a/system/gd/os/linux_generic/reactive_semaphore.cc b/system/gd/os/linux_generic/reactive_semaphore.cc index 47d1ee9406..57fc9d6fe9 100644 --- a/system/gd/os/linux_generic/reactive_semaphore.cc +++ b/system/gd/os/linux_generic/reactive_semaphore.cc @@ -24,7 +24,6 @@ #include <functional> #include "os/linux_generic/linux.h" -#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/linux_generic/reactor.cc b/system/gd/os/linux_generic/reactor.cc index 58a5f93a11..4fc2ac92b3 100644 --- a/system/gd/os/linux_generic/reactor.cc +++ b/system/gd/os/linux_generic/reactor.cc @@ -27,8 +27,6 @@ #include <cinttypes> #include <cstring> -#include "os/log.h" - namespace { // Use at most sizeof(epoll_event) * kEpollMaxEvents kernel memory diff --git a/system/gd/os/linux_generic/reactor_unittest.cc b/system/gd/os/linux_generic/reactor_unittest.cc index de6b829a67..d131f5f74d 100644 --- a/system/gd/os/linux_generic/reactor_unittest.cc +++ b/system/gd/os/linux_generic/reactor_unittest.cc @@ -26,7 +26,6 @@ #include "common/bind.h" #include "common/callback.h" #include "gtest/gtest.h" -#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/linux_generic/repeating_alarm.cc b/system/gd/os/linux_generic/repeating_alarm.cc index f62de8be65..20542228d4 100644 --- a/system/gd/os/linux_generic/repeating_alarm.cc +++ b/system/gd/os/linux_generic/repeating_alarm.cc @@ -24,7 +24,6 @@ #include "common/bind.h" #include "os/linux_generic/linux.h" -#include "os/log.h" #include "os/utils.h" #ifdef __ANDROID__ diff --git a/system/gd/os/linux_generic/thread.cc b/system/gd/os/linux_generic/thread.cc index 9bc2e496b1..33dfb2a229 100644 --- a/system/gd/os/linux_generic/thread.cc +++ b/system/gd/os/linux_generic/thread.cc @@ -24,8 +24,6 @@ #include <cerrno> #include <cstring> -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/os/linux_generic/wakelock_manager.cc b/system/gd/os/linux_generic/wakelock_manager.cc index 022904c942..b8cc9000ba 100644 --- a/system/gd/os/linux_generic/wakelock_manager.cc +++ b/system/gd/os/linux_generic/wakelock_manager.cc @@ -26,7 +26,6 @@ #include <mutex> #include "os/internal/wakelock_native.h" -#include "os/log.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/gd/os/log.h b/system/gd/os/log.h deleted file mode 100644 index 456fbe3f0d..0000000000 --- a/system/gd/os/log.h +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** - * - * Copyright 2019 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 <inttypes.h> - -#include <cstdlib> - -#include "os/logging/log_adapter.h" - -#if defined(__ANDROID__) -#include <log/log.h> -#include <log/log_event_list.h> -#endif // defined(__ANDROID__) diff --git a/system/gd/os/mock_queue.h b/system/gd/os/mock_queue.h index 41aa743e9c..03ede2025b 100644 --- a/system/gd/os/mock_queue.h +++ b/system/gd/os/mock_queue.h @@ -26,7 +26,6 @@ #include "common/bind.h" #include "common/callback.h" #include "os/handler.h" -#include "os/log.h" #include "os/queue.h" namespace bluetooth { diff --git a/system/gd/os/queue.h b/system/gd/os/queue.h index d722c33a4a..fef9073202 100644 --- a/system/gd/os/queue.h +++ b/system/gd/os/queue.h @@ -27,7 +27,6 @@ #include "common/callback.h" #include "os/handler.h" #include "os/linux_generic/reactive_semaphore.h" -#include "os/log.h" namespace bluetooth { namespace os { diff --git a/system/gd/os/rand.h b/system/gd/os/rand.h index edda493b31..e2b0b649fd 100644 --- a/system/gd/os/rand.h +++ b/system/gd/os/rand.h @@ -22,8 +22,6 @@ #include <array> #include <cstdint> -#include "os/log.h" - namespace bluetooth { namespace os { diff --git a/system/gd/packet/Android.bp b/system/gd/packet/Android.bp index 851afb6ccf..c4504a62c8 100644 --- a/system/gd/packet/Android.bp +++ b/system/gd/packet/Android.bp @@ -19,7 +19,10 @@ filegroup { "raw_builder.cc", "view.cc", ], - visibility: ["//visibility:public"], + visibility: [ + "//hardware/interfaces/bluetooth/aidl/vts", + "//packages/modules/Bluetooth/system:__subpackages__", + ], } filegroup { diff --git a/system/gd/packet/bit_inserter_unittest.cc b/system/gd/packet/bit_inserter_unittest.cc index 5c78db51ff..636fa470bd 100644 --- a/system/gd/packet/bit_inserter_unittest.cc +++ b/system/gd/packet/bit_inserter_unittest.cc @@ -20,8 +20,6 @@ #include <memory> -#include "os/log.h" - using bluetooth::packet::BitInserter; using std::vector; diff --git a/system/gd/packet/fragmenting_inserter_unittest.cc b/system/gd/packet/fragmenting_inserter_unittest.cc index dee70a615c..5d90a5a075 100644 --- a/system/gd/packet/fragmenting_inserter_unittest.cc +++ b/system/gd/packet/fragmenting_inserter_unittest.cc @@ -20,8 +20,6 @@ #include <memory> -#include "os/log.h" - using bluetooth::packet::FragmentingInserter; using std::vector; diff --git a/system/gd/packet/packet_builder.h b/system/gd/packet/packet_builder.h index e86af5289d..19a0be1183 100644 --- a/system/gd/packet/packet_builder.h +++ b/system/gd/packet/packet_builder.h @@ -22,7 +22,6 @@ #include <memory> #include <vector> -#include "os/log.h" #include "packet/base_packet_builder.h" #include "packet/bit_inserter.h" #include "packet/endian_inserter.h" diff --git a/system/gd/packet/packet_struct.h b/system/gd/packet/packet_struct.h index 92e3200f35..92ab83e4db 100644 --- a/system/gd/packet/packet_struct.h +++ b/system/gd/packet/packet_struct.h @@ -22,7 +22,6 @@ #include <memory> #include <vector> -#include "os/log.h" #include "packet/base_struct.h" #include "packet/bit_inserter.h" #include "packet/endian_inserter.h" diff --git a/system/gd/packet/parser/test/generated_packet_test.cc b/system/gd/packet/parser/test/generated_packet_test.cc index 66ca1fb7cc..e706e15bee 100644 --- a/system/gd/packet/parser/test/generated_packet_test.cc +++ b/system/gd/packet/parser/test/generated_packet_test.cc @@ -20,7 +20,7 @@ #include <memory> #define PACKET_TESTING -#include "os/log.h" + #include "packet/bit_inserter.h" #include "packet/parser/test/big_endian_test_packets.h" #include "packet/parser/test/six_bytes.h" diff --git a/system/gd/packet/raw_builder.cc b/system/gd/packet/raw_builder.cc index 604d3ee8a1..49ebeed351 100644 --- a/system/gd/packet/raw_builder.cc +++ b/system/gd/packet/raw_builder.cc @@ -19,8 +19,6 @@ #include <algorithm> #include <utility> -#include "os/log.h" - namespace bluetooth { namespace packet { diff --git a/system/gd/rust/linux/stack/src/battery_service.rs b/system/gd/rust/linux/stack/src/battery_service.rs index 688d5fd3ca..013b941260 100644 --- a/system/gd/rust/linux/stack/src/battery_service.rs +++ b/system/gd/rust/linux/stack/src/battery_service.rs @@ -2,7 +2,6 @@ use crate::battery_manager::{Battery, BatterySet}; use crate::battery_provider_manager::{ BatteryProviderManager, IBatteryProviderCallback, IBatteryProviderManager, }; -use crate::bluetooth::BluetoothDevice; use crate::bluetooth_gatt::{ BluetoothGatt, BluetoothGattService, IBluetoothGatt, IBluetoothGattCallback, }; @@ -10,9 +9,9 @@ use crate::callbacks::Callbacks; use crate::Message; use crate::RPCProxy; use crate::{uuid, APIMessage, BluetoothAPI}; -use bt_topshim::btif::{BtAclState, BtBondState, BtTransport, DisplayAddress, RawAddress, Uuid}; +use bt_topshim::btif::{BtTransport, DisplayAddress, RawAddress, Uuid}; use bt_topshim::profiles::gatt::{GattStatus, LePhy}; -use log::debug; +use log::{debug, info}; use std::collections::HashMap; use std::convert::TryInto; use std::iter; @@ -23,6 +22,10 @@ use tokio::sync::mpsc::Sender; /// specification. pub const CHARACTERISTIC_BATTERY_LEVEL: &str = "00002A1-9000-0100-0800-000805F9B34FB"; +/// The app UUID BAS provides when connecting as a GATT client. Chosen at random. +/// TODO(b/233101174): make dynamic or decide on a static UUID +pub const BATTERY_SERVICE_GATT_CLIENT_APP_ID: &str = "e4d2acffcfaa42198f494606b7412117"; + /// Represents the Floss BatteryService implementation. pub struct BatteryService { gatt: Arc<Mutex<Box<BluetoothGatt>>>, @@ -55,10 +58,6 @@ pub enum BatteryServiceActions { OnCharacteristicRead(RawAddress, GattStatus, i32, Vec<u8>), /// Params: addr, handle, value OnNotify(RawAddress, i32, Vec<u8>), - /// Params: remote_device, transport - Connect(BluetoothDevice, BtAclState, BtBondState, BtTransport), - /// Params: remote_device - Disconnect(BluetoothDevice), } /// API for Floss implementation of the Bluetooth Battery Service (BAS). BAS is built on GATT and @@ -127,8 +126,7 @@ impl BatteryService { pub fn init(&self) { debug!("Registering GATT client for BatteryService"); self.gatt.lock().unwrap().register_client( - // TODO(b/233101174): make dynamic or decide on a static UUID - String::from("e4d2acffcfaa42198f494606b7412117"), + String::from(BATTERY_SERVICE_GATT_CLIENT_APP_ID), Box::new(GattCallback::new(self.tx.clone(), self.api_tx.clone())), false, ); @@ -144,6 +142,13 @@ impl BatteryService { BatteryServiceActions::OnClientConnectionState(status, _client_id, connected, addr) => { if !connected || status != GattStatus::Success { + info!( + "BAS: Dropping {} due to GATT state changed: connected={}, status={:?}", + DisplayAddress(&addr), + connected, + status + ); + self.drop_device(addr); return; } let client_id = match self.client_id { @@ -157,8 +162,8 @@ impl BatteryService { BatteryServiceActions::OnSearchComplete(addr, services, status) => { if status != GattStatus::Success { - debug!( - "GATT service discovery for {} failed with status {:?}", + info!( + "BAS: Service discovery for {} failed: status={:?}", DisplayAddress(&addr), status ); @@ -176,10 +181,16 @@ impl BatteryService { ) }); } + info!( + "BAS: Failed to get handle from {}: status={:?}", + DisplayAddress(&addr), + status + ); self.drop_device(addr); return; } }; + info!("BAS: Found handle from {}", DisplayAddress(&addr)); let client_id = match self.client_id { Some(id) => id, None => { @@ -221,21 +232,6 @@ impl BatteryService { callback.on_battery_info_updated(addr, battery_info.clone()); }); } - - BatteryServiceActions::Connect(device, acl_state, bond_state, transport) => { - if transport != BtTransport::Le - || acl_state != BtAclState::Connected - || bond_state != BtBondState::Bonded - { - return; - } - - self.init_device(device.address, transport); - } - - BatteryServiceActions::Disconnect(device) => { - self.drop_device(device.address); - } } } @@ -258,23 +254,22 @@ impl BatteryService { battery_set.clone() } - fn init_device(&self, remote_address: RawAddress, transport: BtTransport) { + pub(crate) fn init_device(&self, remote_address: RawAddress) { let client_id = match self.client_id { Some(id) => id, None => return, }; - debug!("Attempting GATT connection to {}", DisplayAddress(&remote_address)); self.gatt.lock().unwrap().client_connect( client_id, remote_address, false, - transport, + BtTransport::Le, false, LePhy::Phy1m, ); } - fn drop_device(&mut self, remote_address: RawAddress) { + pub(crate) fn drop_device(&mut self, remote_address: RawAddress) { if self.handles.contains_key(&remote_address) { // Let BatteryProviderManager know that BAS no longer has a battery for this device. self.battery_provider_manager.lock().unwrap().remove_battery_info( @@ -354,6 +349,7 @@ impl BatteryService { } /// Status enum for relaying the state of BAS or a particular device. +#[derive(Debug)] pub enum BatteryServiceStatus { /// Device does not report support for BAS. BatteryServiceNotSupported, diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index 3868212fc0..20442315c0 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -43,7 +43,6 @@ use tokio::sync::mpsc::Sender; use tokio::task::JoinHandle; use tokio::time; -use crate::battery_service::BatteryServiceActions; use crate::bluetooth_admin::BluetoothAdminPolicyHelper; use crate::bluetooth_gatt::{ BluetoothGatt, GattActions, IBluetoothGatt, IScannerCallback, ScanResult, @@ -375,6 +374,7 @@ struct BluetoothDeviceContext { pub info: BluetoothDevice, pub last_seen: Instant, pub properties: HashMap<BtPropertyType, BluetoothProperty>, + pub is_hh_connected: bool, /// If user wants to connect to all profiles, when new profiles are discovered we will also try /// to connect them. @@ -398,6 +398,7 @@ impl BluetoothDeviceContext { info, last_seen, properties: HashMap::new(), + is_hh_connected: false, connect_to_new_profiles: false, }; device.update_properties(&properties); @@ -1296,6 +1297,10 @@ impl Bluetooth { || self.pending_create_bond.is_some() } + pub fn is_hh_connected(&self, device_address: &RawAddress) -> bool { + self.remote_devices.get(&device_address).map_or(false, |context| context.is_hh_connected) + } + /// Checks whether the list of device properties contains some UUID we should connect now /// This function also connects those UUIDs. fn check_new_property_and_potentially_connect_profiles( @@ -1417,37 +1422,6 @@ impl Bluetooth { }); } - Profile::Bas => { - has_supported_profile = true; - let tx = self.tx.clone(); - let device_context = match self.remote_devices.get(&addr) { - Some(context) => context, - None => continue, - }; - - let acl_state = device_context.ble_acl_state.clone(); - let bond_state = device_context.bond_state.clone(); - let device_to_send = device.clone(); - - let transport = match self.get_remote_type(device.clone()) { - BtDeviceType::Bredr => BtTransport::Bredr, - BtDeviceType::Ble => BtTransport::Le, - _ => device_context.acl_reported_transport.clone(), - }; - topstack::get_runtime().spawn(async move { - let _ = tx - .send(Message::BatteryService( - BatteryServiceActions::Connect( - device_to_send, - acl_state, - bond_state, - transport, - ), - )) - .await; - }); - } - // We don't connect most profiles _ => (), } @@ -1464,6 +1438,31 @@ impl Bluetooth { self.resume_discovery(); } } + + fn fire_device_connection_or_bonded_state_changed(&self, addr: RawAddress) { + if let Some(device) = self.remote_devices.get(&addr) { + let tx = self.tx.clone(); + let bredr_acl_state = device.bredr_acl_state.clone(); + let ble_acl_state = device.ble_acl_state.clone(); + let bond_state = device.bond_state.clone(); + let transport = match self.get_remote_type(device.info.clone()) { + BtDeviceType::Bredr => BtTransport::Bredr, + BtDeviceType::Ble => BtTransport::Le, + _ => device.acl_reported_transport.clone(), + }; + tokio::spawn(async move { + let _ = tx + .send(Message::OnDeviceConnectionOrBondStateChanged( + addr, + bredr_acl_state, + ble_acl_state, + bond_state, + transport, + )) + .await; + }); + } + } } #[btif_callbacks_dispatcher(dispatch_base_callbacks, BaseCallbacks)] @@ -1933,40 +1932,22 @@ impl BtifBluetoothCallbacks for Bluetooth { Instant::now(), vec![], )); - let acl_reported_transport = device.acl_reported_transport.clone(); - let acl_state = device.ble_acl_state.clone(); let device_info = device.info.clone(); - // Since this is a newly bonded device, we also need to trigger SDP on it. - self.fetch_remote_uuids(device_info.clone()); + self.fetch_remote_uuids(device_info); if self.get_wake_allowed_device_bonded() { self.create_uhid_for_suspend_wakesource(); } // Update the connectable mode since bonded list is changed. self.update_connectable_mode(); - - let transport = match self.get_remote_type(device_info.clone()) { - BtDeviceType::Bredr => BtTransport::Bredr, - BtDeviceType::Ble => BtTransport::Le, - _ => acl_reported_transport, - }; - - let tx = self.tx.clone(); - tokio::spawn(async move { - let _ = tx - .send(Message::OnDeviceConnectionStateChanged( - device_info.clone(), - acl_state, - BtBondState::Bonded, - transport, - )) - .await; - }); } BtBondState::Bonding => {} } } + // Modification to |self.remote_devices| has done, ok to fire the change event. + self.fire_device_connection_or_bonded_state_changed(addr); + // Resume discovery once the bonding process is complete. Discovery was paused before the // bond request to avoid ACL connection from interfering with active inquiry. if bond_state == BtBondState::NotBonded || bond_state == BtBondState::Bonded { @@ -2073,7 +2054,6 @@ impl BtifBluetoothCallbacks for Bluetooth { return; } - let txl = self.tx.clone(); let device = self.remote_devices.entry(addr).or_insert(BluetoothDeviceContext::new( BtBondState::NotBonded, BtAclState::Disconnected, @@ -2090,7 +2070,6 @@ impl BtifBluetoothCallbacks for Bluetooth { let info = device.info.clone(); device.acl_reported_transport = link_type; - let bond_state = device.bond_state.clone(); metrics::acl_connection_state_changed( addr, @@ -2103,26 +2082,10 @@ impl BtifBluetoothCallbacks for Bluetooth { match state { BtAclState::Connected => { - let acl_reported_transport = device.acl_reported_transport; Bluetooth::send_metrics_remote_device_info(device); self.connection_callbacks.for_all_callbacks(|callback| { callback.on_device_connected(info.clone()); }); - let transport = match self.get_remote_type(info.clone()) { - BtDeviceType::Bredr => BtTransport::Bredr, - BtDeviceType::Ble => BtTransport::Le, - _ => acl_reported_transport, - }; - tokio::spawn(async move { - let _ = txl - .send(Message::OnDeviceConnectionStateChanged( - info, - BtAclState::Connected, - bond_state, - transport, - )) - .await; - }); } BtAclState::Disconnected => { if !device.is_connected() { @@ -2131,11 +2094,12 @@ impl BtifBluetoothCallbacks for Bluetooth { }); device.connect_to_new_profiles = false; } - tokio::spawn(async move { - let _ = txl.send(Message::OnDeviceDisconnected(info)).await; - }); } }; + + // Modification to |self.remote_devices| has done, ok to fire the change event. + self.fire_device_connection_or_bonded_state_changed(addr); + // If we are bonding, skip the update here as we will update it after bonding complete anyway. // This is necessary for RTK controllers, which will break RNR after |Write Scan Enable| // command. Although this is a bug of RTK controllers, but as we could avoid unwanted page @@ -2848,18 +2812,6 @@ impl IBluetooth for Bluetooth { }); } - Profile::Bas => { - let tx = self.tx.clone(); - let device_to_send = device.clone(); - topstack::get_runtime().spawn(async move { - let _ = tx - .send(Message::BatteryService( - BatteryServiceActions::Disconnect(device_to_send), - )) - .await; - }); - } - // We don't connect most profiles _ => (), } @@ -3010,7 +2962,7 @@ impl BtifSdpCallbacks for Bluetooth { impl BtifHHCallbacks for Bluetooth { fn connection_state( &mut self, - mut address: RawAddress, + address: RawAddress, address_type: BtAddrType, transport: BtTransport, state: BthhConnectionState, @@ -3047,6 +2999,16 @@ impl BtifHHCallbacks for Bluetooth { state as u32, ); + let tx = self.tx.clone(); + self.remote_devices.entry(address).and_modify(|context| { + if context.is_hh_connected && state != BthhConnectionState::Connected { + tokio::spawn(async move { + let _ = tx.send(Message::ProfileDisconnected(address)).await; + }); + } + context.is_hh_connected = state == BthhConnectionState::Connected; + }); + if BtBondState::Bonded != self.get_bond_state_by_addr(&address) && (state != BthhConnectionState::Disconnecting && state != BthhConnectionState::Disconnected) @@ -3057,6 +3019,7 @@ impl BtifHHCallbacks for Bluetooth { ); // TODO(b/329837967): Determine correct reconnection // behavior based on device instead of the default + let mut address = address; self.hh.as_ref().unwrap().disconnect( &mut address, address_type, diff --git a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs index 10368fbf49..d7361844d0 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs @@ -173,6 +173,14 @@ impl ContextMap { .collect() } + fn get_connected_applications_from_address(&self, address: &RawAddress) -> Vec<Uuid> { + self.get_client_ids_from_address(address) + .into_iter() + .filter_map(|id| self.get_by_client_id(id)) + .map(|client| client.uuid) + .collect() + } + fn get_callback_from_callback_id( &mut self, callback_id: u32, @@ -1872,6 +1880,10 @@ impl BluetoothGatt { pub fn handle_adv_action(&mut self, action: AdvertiserActions) { self.adv_manager.get_impl().handle_action(action); } + + pub(crate) fn get_connected_applications(&self, device_address: &RawAddress) -> Vec<Uuid> { + self.context_map.get_connected_applications_from_address(device_address) + } } #[derive(Debug, FromPrimitive, ToPrimitive)] @@ -2865,6 +2877,11 @@ impl BtifGattClientCallbacks for BluetoothGatt { } } } + + let tx = self.tx.clone(); + tokio::spawn(async move { + let _ = tx.send(Message::ProfileDisconnected(addr)).await; + }); } fn search_complete_cb(&mut self, conn_id: i32, _status: GattStatus) { diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs index b31cc1c7e2..4e6f6d2811 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs @@ -609,6 +609,10 @@ impl BluetoothMedia { false } + pub(crate) fn get_connected_profiles(&self, device_address: &RawAddress) -> HashSet<Profile> { + self.connected_profiles.get(device_address).cloned().unwrap_or_default() + } + fn add_connected_profile(&mut self, addr: RawAddress, profile: Profile) { if self.is_profile_connected(&addr, &profile) { warn!("[{}]: profile is already connected", DisplayAddress(&addr)); @@ -2302,6 +2306,10 @@ impl BluetoothMedia { self.connected_profiles.remove(&addr); states.remove(&addr); guard.remove(&addr); + let tx = self.tx.clone(); + tokio::spawn(async move { + let _ = tx.send(Message::ProfileDisconnected(addr)).await; + }); return; } diff --git a/system/gd/rust/linux/stack/src/lib.rs b/system/gd/rust/linux/stack/src/lib.rs index b13e66b523..e540e68d3e 100644 --- a/system/gd/rust/linux/stack/src/lib.rs +++ b/system/gd/rust/linux/stack/src/lib.rs @@ -20,7 +20,7 @@ pub mod suspend; pub mod uuid; use bluetooth_qa::{BluetoothQA, IBluetoothQA}; -use log::debug; +use log::{debug, info}; use num_derive::{FromPrimitive, ToPrimitive}; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::channel; @@ -29,7 +29,9 @@ use tokio::time::{sleep, Duration}; use crate::battery_manager::{BatteryManager, BatterySet}; use crate::battery_provider_manager::BatteryProviderManager; -use crate::battery_service::{BatteryService, BatteryServiceActions}; +use crate::battery_service::{ + BatteryService, BatteryServiceActions, BATTERY_SERVICE_GATT_CLIENT_APP_ID, +}; use crate::bluetooth::{ dispatch_base_callbacks, dispatch_hid_host_callbacks, dispatch_sdp_callbacks, AdapterActions, Bluetooth, BluetoothDevice, IBluetooth, @@ -45,7 +47,7 @@ use crate::dis::{DeviceInformation, ServiceCallbacks}; use crate::socket_manager::{BluetoothSocketManager, SocketActions}; use crate::suspend::Suspend; use bt_topshim::{ - btif::{BaseCallbacks, BtAclState, BtBondState, BtTransport, RawAddress}, + btif::{BaseCallbacks, BtAclState, BtBondState, BtTransport, DisplayAddress, RawAddress, Uuid}, profiles::{ a2dp::A2dpCallbacks, avrcp::AvrcpCallbacks, @@ -109,8 +111,14 @@ pub enum Message { // Follows IBluetooth's on_device_(dis)connected and bond_state callbacks // but doesn't require depending on Bluetooth. - OnDeviceConnectionStateChanged(BluetoothDevice, BtAclState, BtBondState, BtTransport), - OnDeviceDisconnected(BluetoothDevice), + // Params: Address, BR/EDR ACL state, BLE ACL state, bond state, transport + OnDeviceConnectionOrBondStateChanged( + RawAddress, + BtAclState, + BtAclState, + BtBondState, + BtTransport, + ), // Suspend related SuspendCallbackRegistered(u32), @@ -167,6 +175,11 @@ pub enum Message { // UHid callbacks UHidHfpOutputCallback(RawAddress, u8, u8), UHidTelephonyUseCallback(RawAddress, bool), + + // This message is sent when either HID, media, or GATT client, is disconnected. + // Note that meida sends this when the profiles are disconnected as a whole, that is, it will + // not be called when AVRCP is disconnected but not A2DP, as an example. + ProfileDisconnected(RawAddress), } /// Returns a callable object that dispatches a BTIF callback to Message @@ -432,27 +445,19 @@ impl Stack { bluetooth.lock().unwrap().handle_actions(action); } - // Any service needing an updated list of devices can have an - // update method triggered from here rather than needing a - // reference to Bluetooth. - Message::OnDeviceConnectionStateChanged( - device, - acl_state, + // Any service needing an updated list of devices can have an update method + // triggered from here rather than needing a reference to Bluetooth. + Message::OnDeviceConnectionOrBondStateChanged( + addr, + _bredr_acl_state, + ble_acl_state, bond_state, - transport, + _transport, ) => { - battery_service.lock().unwrap().handle_action(BatteryServiceActions::Connect( - device, acl_state, bond_state, transport, - )); - } - - // For battery service, use this to clean up internal handles. GATT connection is - // already dropped if ACL disconnect has occurred. - Message::OnDeviceDisconnected(device) => { - battery_service - .lock() - .unwrap() - .handle_action(BatteryServiceActions::Disconnect(device)); + if ble_acl_state == BtAclState::Connected && bond_state == BtBondState::Bonded { + info!("BAS: Connecting to {}", DisplayAddress(&addr)); + battery_service.lock().unwrap().init_device(addr); + } } Message::SuspendCallbackRegistered(id) => { @@ -599,6 +604,26 @@ impl Stack { .unwrap() .dispatch_uhid_telephony_use_callback(addr, state); } + + Message::ProfileDisconnected(addr) => { + let bas_app_uuid = + Uuid::from_string(String::from(BATTERY_SERVICE_GATT_CLIENT_APP_ID)) + .expect("BAS Uuid failed to be parsed"); + // Ideally we would also check that there are no open sockets for this device + // but Floss does not manage socket state so there is no reasonable way for us + // to know whether a socket is open or not. + if bluetooth_gatt.lock().unwrap().get_connected_applications(&addr) + == vec![bas_app_uuid] + && !bluetooth.lock().unwrap().is_hh_connected(&addr) + && bluetooth_media.lock().unwrap().get_connected_profiles(&addr).is_empty() + { + info!( + "BAS: Disconnecting from {} since it's the last active profile", + DisplayAddress(&addr) + ); + battery_service.lock().unwrap().drop_device(addr); + } + } } } } diff --git a/system/gd/rust/topshim/csis/csis_shim.cc b/system/gd/rust/topshim/csis/csis_shim.cc index 371d4976f5..c08deb019d 100644 --- a/system/gd/rust/topshim/csis/csis_shim.cc +++ b/system/gd/rust/topshim/csis/csis_shim.cc @@ -21,7 +21,6 @@ #include <string> -#include "os/log.h" #include "src/profiles/csis.rs.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -101,19 +100,18 @@ public: DBusCsisClientCallbacks() {} void OnConnectionState(const RawAddress& addr, csis::ConnectionState state) override { - log::info("addr={}, state={}", ADDRESS_TO_LOGGABLE_CSTR(addr), static_cast<uint8_t>(state)); + log::info("addr={}, state={}", addr, static_cast<uint8_t>(state)); topshim::rust::internal::connection_state_cb(addr, state); } void OnDeviceAvailable(const RawAddress& addr, int group_id, int group_size, int rank, const bluetooth::Uuid& uuid) override { - log::info("addr={}, group_id={}, group_size={}, rank={}", ADDRESS_TO_LOGGABLE_CSTR(addr), - group_id, group_size, rank); + log::info("addr={}, group_id={}, group_size={}, rank={}", addr, group_id, group_size, rank); topshim::rust::internal::device_available_cb(addr, group_id, group_size, rank, uuid); } void OnSetMemberAvailable(const RawAddress& addr, int group_id) { - log::info("addr={}, group_id={}", ADDRESS_TO_LOGGABLE_CSTR(addr), group_id); + log::info("addr={}, group_id={}", addr, group_id); topshim::rust::internal::set_member_available_cb(addr, group_id); } diff --git a/system/gd/rust/topshim/hfp/hfp_shim.cc b/system/gd/rust/topshim/hfp/hfp_shim.cc index 12c338e535..549b54a479 100644 --- a/system/gd/rust/topshim/hfp/hfp_shim.cc +++ b/system/gd/rust/topshim/hfp/hfp_shim.cc @@ -22,7 +22,6 @@ #include "common/strings.h" #include "device/include/interop.h" #include "include/hardware/bt_hf.h" -#include "os/log.h" #include "src/profiles/hfp.rs.h" #include "types/raw_address.h" diff --git a/system/gd/rust/topshim/le_audio/le_audio_shim.cc b/system/gd/rust/topshim/le_audio/le_audio_shim.cc index bb70fc37d0..77d7a5c60d 100644 --- a/system/gd/rust/topshim/le_audio/le_audio_shim.cc +++ b/system/gd/rust/topshim/le_audio/le_audio_shim.cc @@ -22,7 +22,6 @@ #include <vector> #include "bta/le_audio/le_audio_types.h" -#include "os/log.h" #include "src/profiles/le_audio.rs.h" #include "types/raw_address.h" @@ -253,7 +252,7 @@ public: } void OnConnectionState(le_audio::ConnectionState state, const RawAddress& address) override { - log::info("state={}, address={}", static_cast<int>(state), ADDRESS_TO_LOGGABLE_CSTR(address)); + log::info("state={}, address={}", static_cast<int>(state), address); topshim::rust::internal::connection_state_cb(state, address); } @@ -264,8 +263,8 @@ public: void OnGroupNodeStatus(const RawAddress& bd_addr, int group_id, le_audio::GroupNodeStatus node_status) { - log::info("bd_addr={}, group_id={}, node_status={}", ADDRESS_TO_LOGGABLE_CSTR(bd_addr), - group_id, static_cast<int>(node_status)); + log::info("bd_addr={}, group_id={}, node_status={}", bd_addr, group_id, + static_cast<int>(node_status)); topshim::rust::internal::group_node_status_cb(bd_addr, group_id, node_status); } @@ -280,8 +279,7 @@ public: } void OnSinkAudioLocationAvailable(const RawAddress& address, uint32_t snk_audio_locations) { - log::info("address={}, snk_audio_locations={}", ADDRESS_TO_LOGGABLE_CSTR(address), - snk_audio_locations); + log::info("address={}, snk_audio_locations={}", address, snk_audio_locations); topshim::rust::internal::sink_audio_location_available_cb(address, snk_audio_locations); } @@ -323,7 +321,7 @@ public: void OnHealthBasedRecommendationAction(const RawAddress& address, le_audio::LeAudioHealthBasedAction action) { - log::info("address={}, action={}", ADDRESS_TO_LOGGABLE_CSTR(address), static_cast<int>(action)); + log::info("address={}, action={}", address, static_cast<int>(action)); } void OnHealthBasedGroupRecommendationAction(int group_id, diff --git a/system/gd/rust/topshim/vc/vc_shim.cc b/system/gd/rust/topshim/vc/vc_shim.cc index 55d8369db6..f7f68d5af2 100644 --- a/system/gd/rust/topshim/vc/vc_shim.cc +++ b/system/gd/rust/topshim/vc/vc_shim.cc @@ -21,7 +21,6 @@ #include <string> -#include "os/log.h" #include "src/profiles/vc.rs.h" #include "types/raw_address.h" @@ -94,14 +93,14 @@ public: DBusVolumeControlCallbacks() {} void OnConnectionState(vc::ConnectionState state, const RawAddress& address) override { - log::info("state={}, address={}", static_cast<int>(state), ADDRESS_TO_LOGGABLE_CSTR(address)); + log::info("state={}, address={}", static_cast<int>(state), address); topshim::rust::internal::connection_state_cb(state, address); } void OnVolumeStateChanged(const RawAddress& address, uint8_t volume, bool mute, uint8_t flags, bool is_autonomous) override { - log::info("address={}, volume={}, mute={}, flags={}, is_autonomous={}", - ADDRESS_TO_LOGGABLE_CSTR(address), volume, mute, flags, is_autonomous); + log::info("address={}, volume={}, mute={}, flags={}, is_autonomous={}", address, volume, mute, + flags, is_autonomous); topshim::rust::internal::volume_state_cb(address, volume, mute, is_autonomous); } @@ -120,22 +119,19 @@ public: void OnExtAudioOutVolumeOffsetChanged(const RawAddress& address, uint8_t ext_output_id, int16_t offset) override { - log::info("address={}, ext_output_id={}, offset={}", ADDRESS_TO_LOGGABLE_CSTR(address), - ext_output_id, offset); + log::info("address={}, ext_output_id={}, offset={}", address, ext_output_id, offset); topshim::rust::internal::ext_audio_out_volume_offset_cb(address, ext_output_id, offset); } void OnExtAudioOutLocationChanged(const RawAddress& address, uint8_t ext_output_id, uint32_t location) override { - log::info("address={}, ext_output_id, location={}", ADDRESS_TO_LOGGABLE_CSTR(address), - ext_output_id, location); + log::info("address={}, ext_output_id, location={}", address, ext_output_id, location); topshim::rust::internal::ext_audio_out_location_cb(address, ext_output_id, location); } void OnExtAudioOutDescriptionChanged(const RawAddress& address, uint8_t ext_output_id, std::string descr) override { - log::info("address={}, ext_output_id={}, descr={}", ADDRESS_TO_LOGGABLE_CSTR(address), - ext_output_id, descr.c_str()); + log::info("address={}, ext_output_id={}, descr={}", address, ext_output_id, descr.c_str()); topshim::rust::internal::ext_audio_out_description_cb(address, ext_output_id, descr); } diff --git a/system/gd/shim/dumpsys.cc b/system/gd/shim/dumpsys.cc index 24a0083175..30d9f70c0b 100644 --- a/system/gd/shim/dumpsys.cc +++ b/system/gd/shim/dumpsys.cc @@ -30,7 +30,6 @@ #include "main/shim/stack.h" #include "module.h" #include "module_dumper.h" -#include "os/log.h" #include "os/system_properties.h" #include "shim/dumpsys.h" diff --git a/system/gd/stack_manager.cc b/system/gd/stack_manager.cc index d62507400c..856d10a3c4 100644 --- a/system/gd/stack_manager.cc +++ b/system/gd/stack_manager.cc @@ -25,7 +25,6 @@ #include "common/bind.h" #include "module.h" #include "os/handler.h" -#include "os/log.h" #include "os/system_properties.h" #include "os/thread.h" #include "os/wakelock_manager.h" diff --git a/system/gd/storage/device.cc b/system/gd/storage/device.cc index 50d973bdc5..7210a110fe 100644 --- a/system/gd/storage/device.cc +++ b/system/gd/storage/device.cc @@ -21,7 +21,6 @@ #include <algorithm> #include <limits> -#include "os/log.h" #include "storage/classic_device.h" #include "storage/config_cache_helper.h" #include "storage/le_device.h" diff --git a/system/gd/storage/legacy_config_file.cc b/system/gd/storage/legacy_config_file.cc index a64be377ea..0bee52af03 100644 --- a/system/gd/storage/legacy_config_file.cc +++ b/system/gd/storage/legacy_config_file.cc @@ -24,7 +24,6 @@ #include "common/strings.h" #include "os/files.h" -#include "os/log.h" #include "storage/device.h" namespace bluetooth { diff --git a/system/gd/storage/mutation.cc b/system/gd/storage/mutation.cc index c0dacdcc80..559a0415d9 100644 --- a/system/gd/storage/mutation.cc +++ b/system/gd/storage/mutation.cc @@ -16,8 +16,6 @@ #include "storage/mutation.h" -#include "os/log.h" - namespace bluetooth { namespace storage { diff --git a/system/gd/storage/mutation.h b/system/gd/storage/mutation.h index ddaf5804f2..493faddace 100644 --- a/system/gd/storage/mutation.h +++ b/system/gd/storage/mutation.h @@ -17,7 +17,6 @@ #include <queue> -#include "os/log.h" #include "storage/config_cache.h" #include "storage/mutation_entry.h" diff --git a/system/gd/storage/mutation_entry.cc b/system/gd/storage/mutation_entry.cc index 6d078d60a8..f1c930e576 100644 --- a/system/gd/storage/mutation_entry.cc +++ b/system/gd/storage/mutation_entry.cc @@ -16,8 +16,6 @@ #include "storage/mutation_entry.h" -#include "os/log.h" - namespace bluetooth { namespace storage { diff --git a/system/gd/sysprops/sysprops_module.cc b/system/gd/sysprops/sysprops_module.cc index dfb5bfbc5a..0cdcaa2efa 100644 --- a/system/gd/sysprops/sysprops_module.cc +++ b/system/gd/sysprops/sysprops_module.cc @@ -19,7 +19,6 @@ #include <filesystem> #include "os/handler.h" -#include "os/log.h" #include "os/parameter_provider.h" #include "os/system_properties.h" #include "storage/legacy_config_file.h" diff --git a/system/hci/src/packet_fragmenter.cc b/system/hci/src/packet_fragmenter.cc index 9ecb6bd7b5..c95c25dfe6 100644 --- a/system/hci/src/packet_fragmenter.cc +++ b/system/hci/src/packet_fragmenter.cc @@ -28,7 +28,6 @@ #include "hci/include/buffer_allocator.h" #include "hci/include/hci_layer.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" diff --git a/system/include/hardware/bt_vc.h b/system/include/hardware/bt_vc.h index 420e91778b..7d24a07543 100644 --- a/system/include/hardware/bt_vc.h +++ b/system/include/hardware/bt_vc.h @@ -26,6 +26,7 @@ namespace bluetooth { namespace vc { +// Must be kept in sync with BluetoothProfile.java enum class ConnectionState { DISCONNECTED = 0, CONNECTING, CONNECTED, DISCONNECTING }; /* Audio input types */ diff --git a/system/internal_include/bt_target.h b/system/internal_include/bt_target.h index 7aeb11a24f..edb4eb712e 100644 --- a/system/internal_include/bt_target.h +++ b/system/internal_include/bt_target.h @@ -311,7 +311,10 @@ #endif /* Used for conformance testing ONLY: When TRUE lets scriptwrapper overwrite - * info response */ + * info response. + * For testcases L2CAP/FOC/BV-{04,05}-C set property bluetooth.pts.l2cap.foc.bv.test to 4 and + * 5 respectively + */ #ifndef L2CAP_CONFORMANCE_TESTING #define L2CAP_CONFORMANCE_TESTING FALSE #endif diff --git a/system/main/shim/config.cc b/system/main/shim/config.cc index efa9e14221..a2568e455c 100644 --- a/system/main/shim/config.cc +++ b/system/main/shim/config.cc @@ -23,7 +23,6 @@ #include <cstring> #include "main/shim/entry.h" -#include "os/log.h" #include "storage/storage_module.h" using ::bluetooth::shim::GetStorage; diff --git a/system/main/stack_config.cc b/system/main/stack_config.cc index ae5ebc4da5..9b04e7f16c 100644 --- a/system/main/stack_config.cc +++ b/system/main/stack_config.cc @@ -22,7 +22,6 @@ #include <bluetooth/log.h> -#include "os/log.h" #include "osi/include/future.h" using namespace bluetooth; diff --git a/system/osi/src/alarm.cc b/system/osi/src/alarm.cc index 0d515c486d..a280442bb0 100644 --- a/system/osi/src/alarm.cc +++ b/system/osi/src/alarm.cc @@ -32,7 +32,6 @@ #include <mutex> -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" #include "osi/include/list.h" diff --git a/system/osi/src/future.cc b/system/osi/src/future.cc index 63dc254123..ce8c7f0b4b 100644 --- a/system/osi/src/future.cc +++ b/system/osi/src/future.cc @@ -22,7 +22,6 @@ #include <bluetooth/log.h> -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "osi/semaphore.h" diff --git a/system/osi/src/internal/semaphore.cc b/system/osi/src/internal/semaphore.cc index 23aa60c131..8f2706862f 100644 --- a/system/osi/src/internal/semaphore.cc +++ b/system/osi/src/internal/semaphore.cc @@ -27,7 +27,6 @@ #include <sys/eventfd.h> #include <unistd.h> -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" diff --git a/system/osi/src/reactor.cc b/system/osi/src/reactor.cc index 045bc24f3c..82522172c5 100644 --- a/system/osi/src/reactor.cc +++ b/system/osi/src/reactor.cc @@ -30,7 +30,6 @@ #include <mutex> -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/list.h" diff --git a/system/osi/src/socket.cc b/system/osi/src/socket.cc index c1694e68c3..0c7c96b71c 100644 --- a/system/osi/src/socket.cc +++ b/system/osi/src/socket.cc @@ -28,7 +28,6 @@ #include <sys/socket.h> #include <unistd.h> -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "osi/include/reactor.h" diff --git a/system/osi/src/stack_power_telemetry.cc b/system/osi/src/stack_power_telemetry.cc index f8ca11e32c..262bb2afb2 100644 --- a/system/osi/src/stack_power_telemetry.cc +++ b/system/osi/src/stack_power_telemetry.cc @@ -28,7 +28,7 @@ #include <map> #include <mutex> -#include "os/log.h" +#include "os/logging/log_adapter.h" #include "osi/include/properties.h" #include "stack/include/acl_api_types.h" #include "stack/include/bt_psm_types.h" diff --git a/system/osi/src/thread.cc b/system/osi/src/thread.cc index b43a576458..0fa15fc6d3 100644 --- a/system/osi/src/thread.cc +++ b/system/osi/src/thread.cc @@ -32,7 +32,6 @@ #include <atomic> #include <cerrno> -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "osi/include/fixed_queue.h" diff --git a/system/osi/src/wakelock.cc b/system/osi/src/wakelock.cc index 9865ecb16a..5cae5ed580 100644 --- a/system/osi/src/wakelock.cc +++ b/system/osi/src/wakelock.cc @@ -34,7 +34,6 @@ #include <string> #include "common/metrics.h" -#include "os/log.h" #include "osi/include/osi.h" using bluetooth::common::BluetoothMetricsLogger; diff --git a/system/packet/tests/fuzzers/Android.bp b/system/packet/tests/fuzzers/Android.bp index e15bbdc993..00ea544c82 100644 --- a/system/packet/tests/fuzzers/Android.bp +++ b/system/packet/tests/fuzzers/Android.bp @@ -7,11 +7,10 @@ package { default_applicable_licenses: ["system_bt_license"], } -cc_fuzz { - name: "avrcp_browse_packet_fuzzer", +cc_defaults { + name: "packet_avrcp_fuzz_defaults", defaults: ["fluoride_defaults"], host_supported: true, - include_dirs: [ "packages/modules/Bluetooth/system/", "packages/modules/Bluetooth/system/gd", @@ -21,13 +20,6 @@ cc_fuzz { "packages/modules/Bluetooth/system/packet/tests", "packages/modules/Bluetooth/system/packet/tests/avrcp", ], - srcs: [ - "avrcp_browse_packet_fuzzer.cc", - - ], - - corpus: ["corpus/avrcp_browse_packets_corpus/*"], - static_libs: [ "lib-bt-packets", "lib-bt-packets-avrcp", @@ -47,961 +39,176 @@ cc_fuzz { } cc_fuzz { - name: "change_path_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - //system/libbase/include/android-base" - srcs: [ - "change_path_req_fuzzer.cc", - - ], + name: "avrcp_browse_packet_fuzzer", + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["avrcp_browse_packet_fuzzer.cc"], + corpus: ["corpus/avrcp_browse_packets_corpus/*"], +} +cc_fuzz { + name: "change_path_req_fuzzer", + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["change_path_req_fuzzer.cc"], corpus: ["corpus/change_path_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_capabilities_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_capabilities_req_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_capabilities_req_fuzzer.cc"], corpus: ["corpus/get_capabilities_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_capabilities_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_capabilities_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_capabilities_res_fuzzer.cc"], corpus: ["corpus/get_capabilities_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_item_attributes_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_item_attributes_req_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_item_attributes_req_fuzzer.cc"], corpus: ["corpus/get_item_attributes_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_play_status_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_play_status_req_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_play_status_req_fuzzer.cc"], corpus: ["get_play_status_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_total_number_of_items_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_total_number_of_items_req_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_total_number_of_items_req_fuzzer.cc"], corpus: ["corpus/get_total_number_of_items_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "pass_through_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "pass_through_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["pass_through_packet_fuzzer.cc"], corpus: ["corpus/pass_through_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "play_item_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "play_item_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["play_item_packet_fuzzer.cc"], corpus: ["corpus/play_item_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "register_notification_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "register_notification_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["register_notification_packet_fuzzer.cc"], corpus: ["corpus/register_notification_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "set_absolute_volume_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "set_absolute_volume_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["set_absolute_volume_packet_fuzzer.cc"], corpus: ["corpus/set_absolute_volume_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "set_addressed_player_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "set_addressed_player_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["set_addressed_player_packet_fuzzer.cc"], corpus: ["corpus/set_addressed_player_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "set_browsed_player_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "set_browsed_player_req_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["set_browsed_player_req_fuzzer.cc"], corpus: ["corpus/set_browsed_player_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "vendor_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "vendor_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["vendor_packet_fuzzer.cc"], corpus: ["corpus/vendor_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "avrcp_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "avrcp_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["avrcp_packet_fuzzer.cc"], corpus: ["corpus/avrcp_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "reject_packet_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "reject_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["reject_packet_fuzzer.cc"], corpus: ["corpus/reject_packet_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_element_attributes_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_element_attributes_req_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_element_attributes_req_packet_fuzzer.cc"], corpus: ["corpus/get_element_attributes_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "change_path_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "change_path_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["change_path_res_fuzzer.cc"], corpus: ["corpus/change_path_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_element_attributes_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_element_attributes_res_packet_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_element_attributes_res_packet_fuzzer.cc"], corpus: ["corpus/get_element_attributes_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_folder_items_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_folder_items_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_folder_items_res_fuzzer.cc"], corpus: ["corpus/get_folder_items_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_folder_items_req_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_folder_items_req_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_folder_items_req_fuzzer.cc"], corpus: ["corpus/get_folder_items_req_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_item_attributes_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_item_attributes_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_item_attributes_res_fuzzer.cc"], corpus: ["corpus/get_item_attributes_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_play_status_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_play_status_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_play_status_res_fuzzer.cc"], corpus: ["corpus/get_play_status_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "get_total_number_of_items_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "get_total_number_of_items_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["get_total_number_of_items_res_fuzzer.cc"], corpus: ["corpus/get_total_number_of_items_res_corpus/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } cc_fuzz { name: "set_browsed_player_res_fuzzer", - defaults: ["fluoride_defaults"], - host_supported: true, - - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - "packages/modules/Bluetooth/system/packet/base", - "packages/modules/Bluetooth/system/packet/include", - "packages/modules/Bluetooth/system/packet/tests", - "packages/modules/Bluetooth/system/packet/tests/avrcp", - ], - - srcs: [ - "set_browsed_player_res_fuzzer.cc", - - ], - + defaults: ["packet_avrcp_fuzz_defaults"], + srcs: ["set_browsed_player_res_fuzzer.cc"], corpus: ["corpus/set_browsed_player_res_fuzzer/*"], - - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth_log", - "libchrome", - "libgmock", - ], - cflags: [ - "-Wno-missing-prototypes", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "liblog", - ], } diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl index 76673e2aae..df7c47db2a 100644 --- a/system/pdl/hci/hci_packets.pdl +++ b/system/pdl/hci/hci_packets.pdl @@ -4943,7 +4943,7 @@ struct CsOptionalCsSyncPhysSupported { } struct CsOptionalSubfeaturesSupported { - _reserved_ : 1, + companion_signal : 1, frequency_actuation_error : 1, channel_selection_algorithm : 1, phase_based_ranging : 1, @@ -5129,7 +5129,7 @@ enum CsRole : 8 { } enum CsConfigRttType : 8 { - RTT_AA_ONLY = 0x00, + RTT_AA_COARSE = 0x00, RTT_WITH_32_BIT_SOUNDING_SEQUENCE = 0x01, RTT_WITH_96_BIT_SOUNDING_SEQUENCE = 0x02, RTT_WITH_32_BIT_RANDOM_SEQUENCE = 0x03, @@ -6879,7 +6879,6 @@ packet LeCsProcedureEnableComplete : LeMetaEvent (subevent_code = LE_CS_PROCEDUR event_interval : 16, procedure_interval : 16, procedure_count : 16, - max_procedure_len : 16, } struct LeCsMode0InitatorData { diff --git a/system/profile/avrcp/avrcp_internal.h b/system/profile/avrcp/avrcp_internal.h index 665382ce61..a863cb7cf5 100644 --- a/system/profile/avrcp/avrcp_internal.h +++ b/system/profile/avrcp/avrcp_internal.h @@ -16,11 +16,9 @@ #pragma once -#include "avrcp_config.h" #include "stack/include/a2dp_api.h" #include "stack/include/avrc_api.h" #include "stack/include/bt_hdr.h" -#include "stack/include/sdp_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -48,7 +46,7 @@ public: virtual uint16_t Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb, const RawAddress& bd_addr) = 0; - virtual uint16_t OpenBrowse(uint8_t handle, uint8_t conn_role) = 0; + virtual uint16_t OpenBrowse(uint8_t handle, tAVCT_ROLE conn_role) = 0; virtual uint16_t GetPeerMtu(uint8_t handle) = 0; diff --git a/system/profile/avrcp/connection_handler.cc b/system/profile/avrcp/connection_handler.cc index 6faf5cf0e7..9608294161 100644 --- a/system/profile/avrcp/connection_handler.cc +++ b/system/profile/avrcp/connection_handler.cc @@ -233,14 +233,14 @@ bool ConnectionHandler::AvrcpConnect(bool initiator, const RawAddress& bdaddr) { } open_cb.msg_cback = base::Bind(&ConnectionHandler::MessageCb, weak_ptr_factory_.GetWeakPtr()); open_cb.company_id = AVRC_CO_GOOGLE; - open_cb.conn = initiator ? AVRC_CONN_INT : AVRC_CONN_ACP; // 0 if initiator, 1 if acceptor + open_cb.conn = initiator ? AVCT_ROLE_INITIATOR : AVCT_ROLE_ACCEPTOR; // TODO (apanicke): We shouldn't need RCCT to do absolute volume. The current // AVRC_API requires it though. open_cb.control = BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA | AVRC_CT_PASSIVE; uint8_t handle = 0; uint16_t status = avrc_->Open(&handle, &open_cb, bdaddr); - log::info("handle=0x{:x} status= 0x{:x}", handle, status); + log::info("handle=0x{:x} status=0x{:x}", handle, status); return status == AVRC_SUCCESS; } @@ -266,7 +266,7 @@ void ConnectionHandler::InitiatorControlCb(uint8_t handle, uint8_t event, uint16 bool supports_browsing = feature_iter->second & BTA_AV_FEAT_BROWSE; if (supports_browsing) { - avrc_->OpenBrowse(handle, AVCT_INT); + avrc_->OpenBrowse(handle, AVCT_ROLE_INITIATOR); } // TODO (apanicke): Implement a system to cache SDP entries. For most @@ -395,7 +395,7 @@ void ConnectionHandler::AcceptorControlCb(uint8_t handle, uint8_t event, uint16_ }; if (SdpLookup(*peer_addr, base::Bind(sdp_lambda, this, handle), false)) { - avrc_->OpenBrowse(handle, AVCT_ACP); + avrc_->OpenBrowse(handle, AVCT_ROLE_ACCEPTOR); } else { // SDP search failed, this could be due to a collision between outgoing // and incoming connection. In any case, we need to reject the current diff --git a/system/profile/avrcp/tests/avrcp_connection_handler_test.cc b/system/profile/avrcp/tests/avrcp_connection_handler_test.cc index 73334576f1..080bda09f3 100644 --- a/system/profile/avrcp/tests/avrcp_connection_handler_test.cc +++ b/system/profile/avrcp/tests/avrcp_connection_handler_test.cc @@ -206,7 +206,7 @@ TEST_F(AvrcpConnectionHandlerTest, remoteDeviceConnectionTest) { // Set an Expectation that OpenBrowse will be called in acceptor mode when the // device connects. - EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ACP)).Times(1); + 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 @@ -374,7 +374,7 @@ TEST_F(AvrcpConnectionHandlerTest, multipleRemoteDeviceConnectionTest) { // Set an Expectation that OpenBrowse will be called in acceptor mode when the // device connects on handle 1 - EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ACP)).Times(1); + EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ROLE_ACCEPTOR)).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); @@ -391,7 +391,7 @@ TEST_F(AvrcpConnectionHandlerTest, multipleRemoteDeviceConnectionTest) { // Set an Expectation that OpenBrowse will be called in acceptor mode when the // device connects on handle 2 - EXPECT_CALL(mock_avrcp_, OpenBrowse(2, AVCT_ACP)).Times(1); + EXPECT_CALL(mock_avrcp_, OpenBrowse(2, AVCT_ROLE_ACCEPTOR)).Times(1); // Call the callback with a message saying that a remote device has connected // with a different address @@ -504,7 +504,7 @@ TEST_F(AvrcpConnectionHandlerTest, connectToBrowsableRemoteDeviceTest) { // Set an Expectation that OpenBrowse will be called since browsing is listed // as supported in SDP - EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_INT)).Times(1); + EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ROLE_INITIATOR)).Times(1); // Call the callback with a message saying that a remote device has connected // with a different address diff --git a/system/profile/avrcp/tests/avrcp_test_helper.h b/system/profile/avrcp/tests/avrcp_test_helper.h index 7a2f63ab2a..ea6ed4d828 100644 --- a/system/profile/avrcp/tests/avrcp_test_helper.h +++ b/system/profile/avrcp/tests/avrcp_test_helper.h @@ -80,7 +80,7 @@ public: MOCK_METHOD4(FindService, uint16_t(uint16_t, const RawAddress&, tAVRC_SDP_DB_PARAMS*, tAVRC_FIND_CBACK)); MOCK_METHOD3(Open, uint16_t(uint8_t*, tAVRC_CONN_CB*, const RawAddress&)); - MOCK_METHOD2(OpenBrowse, uint16_t(uint8_t, uint8_t)); + MOCK_METHOD2(OpenBrowse, uint16_t(uint8_t, tAVCT_ROLE)); MOCK_METHOD1(GetPeerMtu, uint16_t(uint8_t)); MOCK_METHOD1(GetBrowseMtu, uint16_t(uint8_t)); MOCK_METHOD1(Close, uint16_t(uint8_t)); diff --git a/system/profile/sdp/Android.bp b/system/profile/sdp/Android.bp deleted file mode 100644 index 88e491644f..0000000000 --- a/system/profile/sdp/Android.bp +++ /dev/null @@ -1,60 +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"], -} - -cc_library_static { - name: "sdp_service", - defaults: [ - "fluoride_defaults", - ], - host_supported: true, - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - ], - srcs: [ - "common/data_element_reader.cc", - ], - static_libs: [ - "lib-bt-packets", - "libbluetooth-types", - "libbluetooth_log", - ], - header_libs: ["libbluetooth_headers"], -} - -cc_test { - name: "bluetooth_test_sdp", - test_suites: ["general-tests"], - defaults: [ - "fluoride_defaults", - "mts_defaults", - ], - host_supported: true, - include_dirs: [ - "packages/modules/Bluetooth/system/", - "packages/modules/Bluetooth/system/gd", - ], - srcs: [ - "common/test/data_element_reader_test.cc", - ], - static_libs: [ - "lib-bt-packets", - "lib-bt-packets-avrcp", - "lib-bt-packets-base", - "libbluetooth-types", - "libbluetooth_log", - "libchrome", - "libgmock", - "sdp_service", - ], - shared_libs: [ - "libbase", - "liblog", - ], -} diff --git a/system/profile/sdp/common/data_element_reader.cc b/system/profile/sdp/common/data_element_reader.cc deleted file mode 100644 index 95c4d57e15..0000000000 --- a/system/profile/sdp/common/data_element_reader.cc +++ /dev/null @@ -1,238 +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 "data_element_reader.h" - -#include <bluetooth/log.h> - -#include <type_traits> - -#include "sdp_logging_helper.h" -#include "types/bluetooth/uuid.h" - -// A helper macro that can verify that there is enough data remaining in the -// reader to extract without overflowing. end_ - it_ should never be negative -// so casting it to a size_t is always safe. If it does fail, set it_ to end_ -// so that all additional readings fail. -#define CHECK_REMAINING_LEN(x) \ - do { \ - if ((size_t)(end_ - it_) < x) { \ - log::warn("Extract would read past end of data."); \ - return ParseFail(); \ - } \ - } while (0) - -namespace bluetooth { -namespace sdp { - -DataElementReader::DataElement DataElementReader::ReadNext() { - if (it_ > end_) { - log::fatal("Beginning of buffer is past end of buffer."); - } - if (it_ == end_) { - return std::monostate(); - } - - uint8_t descriptor = *it_++; - DataElementType type = static_cast<DataElementType>(descriptor >> 3); - DataElementSize size = static_cast<DataElementSize>(descriptor & 0b00000111); - - // All types with a value greater than URL are currently reserved. - if (type > DataElementType::MAX_VALUE) { - log::warn("Trying to use a reserved data element type"); - return ParseFail(); - } - - switch (type) { - case DataElementType::BOOLEAN: - if (size != DataElementSize::BYTE1) { - log::warn("Invalid size for bool: {}", size); - return ParseFail(); - } - - CHECK_REMAINING_LEN(1); - return it_.extract<uint8_t>() != 0; - case DataElementType::SIGNED_INT: - return ReadSignedInt(size); - case DataElementType::UNSIGNED_INT: - return ReadUnsignedInt(size); - case DataElementType::UUID: - return ReadUuid(size); - case DataElementType::STRING: - return ReadString(size); - case DataElementType::DATA_ELEMENT_SEQUENCE: - return ReadSequence(size); - default: - // TODO: The other data element types are never used in the previous SDP - // implementation. We should properly handle them in the future though - // for completeness. - log::error("Unhandled Data Element Type: {}", type); - } - - return ParseFail(); -} - -DataElementReader::DataElement DataElementReader::ParseFail() { - it_ = end_; - return std::monostate(); -} - -template <class IntegerType> -DataElementReader::DataElement DataElementReader::ReadInteger() { - static_assert(std::is_integral<IntegerType>::value, "ReadInteger requires an integral type."); - - CHECK_REMAINING_LEN(sizeof(IntegerType)); - return it_.extractBE<IntegerType>(); -} - -DataElementReader::DataElement DataElementReader::ReadLargeInt() { - CHECK_REMAINING_LEN(16); - - std::array<uint8_t, 16> array; - for (size_t i = 0; i < sizeof(uint8_t[16]); i++) { - array[i] = it_.extract<uint8_t>(); - } - - return array; -} - -DataElementReader::DataElement DataElementReader::ReadSignedInt(DataElementSize size) { - switch (size) { - case DataElementSize::BYTE1: - return ReadInteger<int8_t>(); - case DataElementSize::BYTE2: - return ReadInteger<int16_t>(); - case DataElementSize::BYTE4: - return ReadInteger<int32_t>(); - case DataElementSize::BYTE8: - return ReadInteger<int64_t>(); - case DataElementSize::BYTE16: - return ReadLargeInt(); - default: - log::warn("Invalid size for int: {}", size); - } - - return ParseFail(); -} - -DataElementReader::DataElement DataElementReader::ReadUnsignedInt(DataElementSize size) { - switch (size) { - case DataElementSize::BYTE1: - return ReadInteger<uint8_t>(); - case DataElementSize::BYTE2: - return ReadInteger<uint16_t>(); - case DataElementSize::BYTE4: - return ReadInteger<uint32_t>(); - case DataElementSize::BYTE8: - return ReadInteger<uint64_t>(); - case DataElementSize::BYTE16: - return ReadLargeInt(); - default: - log::warn("Invalid size for uint: {}", size); - } - - return ParseFail(); -} - -DataElementReader::DataElement DataElementReader::ReadUuid(DataElementSize size) { - if (size == DataElementSize::BYTE2) { - CHECK_REMAINING_LEN(2); - return Uuid::From16Bit(it_.extractBE<uint16_t>()); - } - - if (size == DataElementSize::BYTE4) { - CHECK_REMAINING_LEN(4); - return Uuid::From32Bit(it_.extractBE<uint32_t>()); - } - - if (size == DataElementSize::BYTE16) { - CHECK_REMAINING_LEN(16); - - Uuid::UUID128Bit uuid_array; - for (int i = 0; i < 16; i++) { - uuid_array[i] = it_.extract<uint8_t>(); - } - - return Uuid::From128BitBE(uuid_array); - } - - log::warn("Invalid size for UUID: {}", size); - return ParseFail(); -} - -DataElementReader::DataElement DataElementReader::ReadString(DataElementSize size) { - uint32_t num_bytes = 0; - - switch (size) { - case DataElementSize::ADDITIONAL_8BIT: - CHECK_REMAINING_LEN(1); - num_bytes = it_.extractBE<uint8_t>(); - break; - case DataElementSize::ADDITIONAL_16BIT: - CHECK_REMAINING_LEN(2); - num_bytes = it_.extractBE<uint16_t>(); - break; - case DataElementSize::ADDITIONAL_32BIT: - CHECK_REMAINING_LEN(4); - num_bytes = it_.extractBE<uint32_t>(); - break; - default: - log::warn("Invalid size for string: {}", size); - return ParseFail(); - } - - CHECK_REMAINING_LEN(num_bytes); - - std::string str; - for (uint32_t i = 0; i < num_bytes; i++) { - str.push_back(it_.extractBE<uint8_t>()); - } - - return str; -} - -DataElementReader::DataElement DataElementReader::ReadSequence(DataElementSize size) { - uint32_t num_bytes = 0; - - switch (size) { - case DataElementSize::ADDITIONAL_8BIT: - CHECK_REMAINING_LEN(1); - num_bytes = it_.extractBE<uint8_t>(); - break; - case DataElementSize::ADDITIONAL_16BIT: - CHECK_REMAINING_LEN(2); - num_bytes = it_.extractBE<uint16_t>(); - break; - case DataElementSize::ADDITIONAL_32BIT: - CHECK_REMAINING_LEN(4); - num_bytes = it_.extractBE<uint32_t>(); - break; - default: - log::warn("Invalid size for string: {}", size); - return ParseFail(); - } - - CHECK_REMAINING_LEN(num_bytes); - - // Create a parser that points to the beginning of the next sequence and move - // the iterator to past the end of the new sequence. - auto&& temp = DataElementReader(it_, it_ + num_bytes); - it_ += num_bytes; - return std::move(temp); -} - -} // namespace sdp -} // namespace bluetooth diff --git a/system/profile/sdp/common/data_element_reader.h b/system/profile/sdp/common/data_element_reader.h deleted file mode 100644 index eea58ece43..0000000000 --- a/system/profile/sdp/common/data_element_reader.h +++ /dev/null @@ -1,64 +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. - */ - -#pragma once - -#include <array> -#include <variant> - -#include "bluetooth/uuid.h" -#include "packet.h" -#include "sdp_common.h" -#include "stack/include/bt_octets.h" - -namespace bluetooth { -namespace sdp { - -// A helper class that helps extract data element objects from SDP packets. -class DataElementReader { -public: - // If the DataElement contains monostate, that means parsing has failed. - using DataElement = - std::variant<std::monostate, bool, int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, - uint32_t, uint64_t, Octet16, Uuid, std::string, DataElementReader>; - - DataElementReader(Iterator begin, Iterator end) : it_(begin), end_(end) {} - - // Get the next Data Element in the data. If reading fails for any reason, - // the DataElementReader becomes invalid and will continuously fail to read - // from that point onward. - DataElement ReadNext(); - -private: - // Extraction Helpers - DataElement ParseFail(); - template <class IntegerType> - DataElement ReadInteger(); - DataElement ReadLargeInt(); - - // Extraction Functions - DataElement ReadSignedInt(DataElementSize size); - DataElement ReadUnsignedInt(DataElementSize size); - DataElement ReadUuid(DataElementSize size); - DataElement ReadString(DataElementSize size); - DataElement ReadSequence(DataElementSize size); - - Iterator it_; - Iterator end_; -}; - -} // namespace sdp -} // namespace bluetooth diff --git a/system/profile/sdp/common/test/data_element_reader_test.cc b/system/profile/sdp/common/test/data_element_reader_test.cc deleted file mode 100644 index 3203098e0d..0000000000 --- a/system/profile/sdp/common/test/data_element_reader_test.cc +++ /dev/null @@ -1,382 +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/data_element_reader.h" - -#include <gtest/gtest.h> - -#include "types/bluetooth/uuid.h" - -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - -namespace bluetooth { -namespace sdp { - -using namespace testing; -using DataElement = DataElementReader::DataElement; - -// A helper class to help work with the Data Element classes. -class ReaderPacket : public ::bluetooth::Packet { -public: - using Packet::Packet; - - static std::shared_ptr<ReaderPacket> Make(std::vector<uint8_t> payload) { - auto pkt = std::shared_ptr<ReaderPacket>(new ReaderPacket()); - pkt->packet_start_index_ = 0; - pkt->packet_end_index_ = payload.size(); - pkt->data_ = std::make_shared<std::vector<uint8_t>>(std::move(payload)); - return pkt; - } - - std::string ToString() const override { return ""; } - bool IsValid() const override { return true; } - std::pair<size_t, size_t> GetPayloadIndecies() const override { - return std::pair<size_t, size_t>(packet_start_index_, packet_end_index_); - } -}; - -bool operator!=(DataElementReader a, DataElementReader b); - -// A helper function to help compare DataElementReader objects. -bool operator==(DataElementReader a, DataElementReader b) { - while (true) { - DataElement a_elem = a.ReadNext(); - DataElement b_elem = b.ReadNext(); - - if (a_elem != b_elem) { - return false; - } - - // If we get here that means both a and b have reached the end. - if (a_elem == DataElement(std::monostate())) { - break; - } - } - - return true; -} - -bool operator!=(DataElementReader a, DataElementReader b) { return !(a == b); } - -// A helper function to convert a type and a size to a descriptor byte. -constexpr uint8_t Desc(DataElementType t, DataElementSize s) { - return static_cast<uint8_t>(t) << 3 | static_cast<uint8_t>(s); -} - -// Helper that can create a Data Element reader from a vector. -DataElementReader CreateReader(std::vector<uint8_t> payload) { - auto packet = ReaderPacket::Make(std::move(payload)); - return DataElementReader(packet->begin(), packet->end()); -} - -// Test all the valid cases of reading the next Data Element. -using ValidTestParam = std::tuple<std::vector<uint8_t>, DataElement>; -class ValidReadTest : public TestWithParam<ValidTestParam> {}; - -std::vector<ValidTestParam> valid_values = { - // Boolean Tests - ValidTestParam{ - {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01}, - true, - }, - ValidTestParam{ - {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00}, - false, - }, - - // Signed Integer Tests - ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE1), 0xFF}, - static_cast<int8_t>(-1)}, - ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0xFF, 0xFF}, - static_cast<int16_t>(-1)}, - ValidTestParam{ - {Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE4), 0xFF, 0xFF, 0xFF, 0xFF}, - static_cast<int32_t>(-1)}, - ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE8), 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - static_cast<int64_t>(-1)}, - ValidTestParam{ - {Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE16), 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - std::array<uint8_t, 16>{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, - - // Unsigned Integer Tests - ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE1), 0x01}, - static_cast<uint8_t>(1)}, - ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE2), 0x00, 0x01}, - static_cast<uint16_t>(1)}, - ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE4), 0x00, 0x00, - 0x00, 0x01}, - static_cast<uint32_t>(1)}, - ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE8), 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - static_cast<uint64_t>(1)}, - ValidTestParam{ - {Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE16), 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - std::array<uint8_t, 16>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - - // UUID Tests - ValidTestParam{{Desc(DataElementType::UUID, DataElementSize::BYTE2), 0x01, 0x02}, - Uuid::From16Bit(0x0102)}, - ValidTestParam{ - {Desc(DataElementType::UUID, DataElementSize::BYTE4), 0x01, 0x02, 0x03, 0x04}, - Uuid::From32Bit(0x01020304)}, - ValidTestParam{ - {Desc(DataElementType::UUID, DataElementSize::BYTE16), 0x00, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}, - Uuid::From128BitBE({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F})}, - - // String Tests - ValidTestParam{{Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT), 0x05, 'T', - 'e', 's', 't', '1'}, - std::string("Test1")}, - ValidTestParam{{Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_16BIT), 0x00, - 0x05, 'T', 'e', 's', 't', '2'}, - std::string("Test2")}, - ValidTestParam{{Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_32BIT), 0x00, - 0x00, 0x00, 0x05, 'T', 'e', 's', 't', '3'}, - std::string("Test3")}, - - // Nested Data Element List Tests - ValidTestParam{ - {Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_8BIT), - 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01, - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00}, - CreateReader({Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01, - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})}, - ValidTestParam{ - {Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_16BIT), - 0x00, 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01, - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00}, - CreateReader({Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01, - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})}, - ValidTestParam{ - {Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_32BIT), - 0x00, 0x00, 0x00, 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), - 0x01, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00}, - CreateReader({Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01, - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})}, -}; - -INSTANTIATE_TEST_CASE_P(ReadNext, ValidReadTest, ValuesIn(valid_values)); -TEST_P(ValidReadTest, Test) { - auto packet = ReaderPacket::Make(std::get<0>(GetParam())); - auto value = std::get<1>(GetParam()); - - DataElementReader reader(packet->begin(), packet->end()); - auto read_value = reader.ReadNext(); - - ASSERT_EQ(value, read_value); - - // Test that there is no additional data to read. - ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate())); -} - -// Test that a nested reader is correctly bounded and can't read past its -// defined end. -TEST(ReadNext, BoundedSubreaderTest) { - std::vector<uint8_t> payload = { - // Subsequence descriptor byte. - Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_8BIT), - // Subsequence length. - 0x04, - // Subsequence that contains two booleans with values true and false. - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01, - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00, - // Additional int16 at the end of the original sequence. - Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0x01, 0x23}; - - auto packet = ReaderPacket::Make(payload); - DataElementReader reader(packet->begin(), packet->end()); - - // The first thing read should be the subsequence. - auto data_element = reader.ReadNext(); - ASSERT_TRUE(std::holds_alternative<DataElementReader>(data_element)); - - // Check that the subsequence matches the premade sequence. - auto subreader = std::get<DataElementReader>(data_element); - data_element = subreader.ReadNext(); - ASSERT_TRUE(std::holds_alternative<bool>(data_element)); - ASSERT_TRUE(std::get<bool>(data_element)); - data_element = subreader.ReadNext(); - ASSERT_TRUE(std::holds_alternative<bool>(data_element)); - ASSERT_FALSE(std::get<bool>(data_element)); - - // Check that there is no additional data to be read from the subreader. - ASSERT_EQ(subreader.ReadNext(), DataElement(std::monostate())); - - // Check that we can still read the int16 from the original reader. - data_element = reader.ReadNext(); - ASSERT_TRUE(std::holds_alternative<int16_t>(data_element)); - auto int16_value = std::get<int16_t>(data_element); - ASSERT_EQ(int16_value, 0x0123); - - // Check that there is no additional data to be read from the base reader. - ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate())); -} - -// Test that trying to read an empty packet fails. -TEST(ReadNext, NoDataTest) { - auto packet = ReaderPacket::Make({}); - DataElementReader reader(packet->begin(), packet->end()); - - ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate())); -} - -// Test that using a reserved value for type fails. -TEST(ReadNext, InvalidTypeTest) { - auto packet = ReaderPacket::Make({0xFF}); - DataElementReader reader(packet->begin(), packet->end()); - - ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate())); -} - -// Test all invalid parses due to incorrect lengths or invalid sizes. All tests -// should return std::monostate. -using InvalidTestParam = std::vector<uint8_t>; -class InvalidReadTest : public TestWithParam<InvalidTestParam> {}; - -std::vector<InvalidTestParam> invalid_values = { - // Boolean Tests: - // Invalid size field. - InvalidTestParam{ - Desc(DataElementType::BOOLEAN, DataElementSize::BYTE2), - }, - // Insufficient data. - InvalidTestParam{Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1)}, - - // Signed Integer Tests: - // Invalid size field. - InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::ADDITIONAL_8BIT)}, - // 1 byte insufficient data. - InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE1)}, - // 2 byte insufficient data. - InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0x00}, - // 4 byte insufficient data. - InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE4), 0x00, 0x00, - 0x00}, - // 8 Byte insufficient data. - InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE8), 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}, - // 16 Byte insufficient data. - InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE16), 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - // Unsigned Integer Tests: - // Invalid size field. - InvalidTestParam{Desc(DataElementType::UNSIGNED_INT, DataElementSize::ADDITIONAL_8BIT)}, - // 1 byte insufficient data. - InvalidTestParam{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE1)}, - // 2 byte insufficient data. - InvalidTestParam{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE2), 0x00}, - // 4 byte insufficient data. - InvalidTestParam{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE4), 0x00, 0x00, - 0x00}, - // 8 Byte insufficient data. - InvalidTestParam{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE8), 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}, - // 16 Byte insufficient data. - InvalidTestParam{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE16), 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - // UUID Tests: - // Invalid size field. - InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::ADDITIONAL_8BIT)}, - // 2 byte insufficient data. - InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE2), 0x00}, - // 4 byte insufficient data. - InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE4), 0x00, 0x00, 0x00}, - // 16 Byte insufficient data. - InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE16), 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - // String Tests: - // Invalid size field. - InvalidTestParam{Desc(DataElementType::STRING, DataElementSize::BYTE1)}, - // Insufficient data for additional 8 bits len. - InvalidTestParam{Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT)}, - // Insufficient data for additional 16 bits len. - InvalidTestParam{ - Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_16BIT), - 0x00, - }, - // Insufficient data for additional 32 bit len. - InvalidTestParam{ - Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_32BIT), - 0x00, - 0x00, - 0x00, - }, - // Insufficient data for reported length. - InvalidTestParam{Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT), 0x04, '1', - '2', '3'}, - - // Nested Data Element List Tests: - // Invalid size field. - InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::BYTE1)}, - // Insufficient data for additional 8 bits len. - InvalidTestParam{ - Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_8BIT)}, - // Insufficient data for additional 16 bits len. - InvalidTestParam{ - Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_16BIT), - 0x00, - }, - // Insufficient data for additional 32 bit len. - InvalidTestParam{ - Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_32BIT), - 0x00, - 0x00, - 0x00, - }, - // Insufficient data for reported length. - InvalidTestParam{ - Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::ADDITIONAL_8BIT), - 0x04, 0x00, 0x00, 0x00}, - - // Unhandled Data Element Types Tests: - // NOTE: These tests should go away as we begin to handle the types. - // Nil Type. - InvalidTestParam{Desc(DataElementType::NIL, DataElementSize::BYTE1)}, - // Data Element Alternative List Type. - InvalidTestParam{ - Desc(DataElementType::DATA_ELEMENT_ALTERNATIVE, DataElementSize::ADDITIONAL_8BIT), - 0x00}, - // URL Type. - InvalidTestParam{Desc(DataElementType::URL, DataElementSize::ADDITIONAL_8BIT), 0x00}}; - -INSTANTIATE_TEST_CASE_P(ReadNext, InvalidReadTest, ValuesIn(invalid_values)); -TEST_P(InvalidReadTest, Test) { - auto packet = ReaderPacket::Make(GetParam()); - DataElementReader reader(packet->begin(), packet->end()); - - ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate())); -} - -// Test that trying to read from a reader with start > end crashes. -TEST(DataElementReader, BadBoundsDeathTest) { - auto packet = ReaderPacket::Make({0x00, 0x00, 0x00, 0x00}); - DataElementReader reader(packet->end(), packet->begin()); - ASSERT_DEATH(reader.ReadNext(), "Beginning of buffer is past end of buffer."); -} - -} // namespace sdp -} // namespace bluetooth diff --git a/system/profile/sdp/sdp_common.h b/system/profile/sdp/sdp_common.h deleted file mode 100644 index 4a07a6306d..0000000000 --- a/system/profile/sdp/sdp_common.h +++ /dev/null @@ -1,95 +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. - */ - -#pragma once - -namespace bluetooth { -namespace sdp { - -enum class PduId : uint8_t { - RESERVED = 0x00, - ERROR = 0x01, - SERVICE_SEARCH_REQUEST = 0x02, - SERVICE_SEARCH_RESPONSE = 0x03, - SERVICE_ATTRIBUTE_REQUEST = 0x04, - SERVICE_ATTRIBUTE_RESPONSE = 0x05, - SERVICE_SEARCH_ATTRIBUTE_REQUEST = 0x06, - SERVICE_SEARCH_ATTRIBUTE_RESPONSE = 0x07, - MAX_VALUE = 0x07, -}; - -enum class AttributeId : uint16_t { - SERVICE_RECORD_HANDLE = 0x0000, - SERVICE_CLASS_ID_LIST = 0x0001, - SERVICE_RECORD_STATE = 0x0002, - SERVICE_ID = 0x0003, - PROTOCOL_DESCRIPTOR_LIST = 0x0004, - BROWSE_GROUP_LIST = 0x0005, - LANGUAGE_BASE_ATTRIBUTE_ID_LIST = 0x0006, - SERVICE_INFO_TIME_TO_LIVE = 0x0007, - SERVICE_AVAILABILITY = 0x0008, - PROFILE_DESCRIPTOR_LIST = 0x0009, - DOCUMENTATION_URL = 0x000A, - CLIENT_EXECUTABLE_URL = 0x000B, - ICON_URL = 0x000C, - ADDITIONAL_PROTOCOL_DESCRIPTOR_LIST = 0x000D, - - // The following attributes are only used in the SDP server service record. - // They are only valid if ServiceDiscoveryServerServiceClassID is in the - // ServiceClassIDList. See Bluetooth Core v5.0 Section 5.2. - VERSION_NUMBER_LIST = 0x0200, - SERVICE_DATABASE_STATE = 0x0201, -}; - -// The Attribute ID's of these attributes are calculated by adding the offset -// value for the attribute to the attribute ID base (contained in the -// LanguageBaseAttributeIDList attribute value). -enum AttributeIdOffset : uint16_t { - SERVICE_NAME = 0x0000, - SERVICE_DESCRIPTION = 0x0001, - PROVIDER_NAME = 0x0002, -}; - -// Constant that define the different types of data element. -enum class DataElementType : uint8_t { - NIL = 0x00, - UNSIGNED_INT = 0x01, - SIGNED_INT = 0x02, - UUID = 0x03, - STRING = 0x04, - BOOLEAN = 0x05, - DATA_ELEMENT_SEQUENCE = 0x06, - DATA_ELEMENT_ALTERNATIVE = 0x07, - URL = 0x08, - MAX_VALUE = 0x08, -}; - -// Constant that define the different sizes of data element. -enum class DataElementSize : uint8_t { - BYTE1 = 0x0, // Exception: If the data element is NIL then size is 0 bytes - BYTE2 = 0x1, - BYTE4 = 0x2, - BYTE8 = 0x3, - BYTE16 = 0x4, - // The size types below represent that the first X bits of the value - // represents the size of the remaining data. - ADDITIONAL_8BIT = 0x5, - ADDITIONAL_16BIT = 0x6, - ADDITIONAL_32BIT = 0x7, -}; - -} // namespace sdp -} // namespace bluetooth diff --git a/system/profile/sdp/sdp_logging_helper.h b/system/profile/sdp/sdp_logging_helper.h deleted file mode 100644 index 4a8d178296..0000000000 --- a/system/profile/sdp/sdp_logging_helper.h +++ /dev/null @@ -1,128 +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. - */ - -#pragma once - -#include <bluetooth/log.h> - -#include <iomanip> -#include <iostream> -#include <sstream> -#include <string> -#include <type_traits> - -#include "macros.h" -#include "sdp_common.h" - -namespace bluetooth { -namespace sdp { - -inline std::string PduIdText(const PduId& id) { - switch (id) { - CASE_RETURN_TEXT(PduId::RESERVED); - CASE_RETURN_TEXT(PduId::ERROR); - CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_REQUEST); - CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_RESPONSE); - CASE_RETURN_TEXT(PduId::SERVICE_ATTRIBUTE_REQUEST); - CASE_RETURN_TEXT(PduId::SERVICE_ATTRIBUTE_RESPONSE); - CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_ATTRIBUTE_REQUEST); - CASE_RETURN_TEXT(PduId::SERVICE_SEARCH_ATTRIBUTE_RESPONSE); - default: - return fmt::format("Unknown PduId: 0x{:x}", (uint8_t)id); - } -} - -inline std::ostream& operator<<(std::ostream& os, const PduId& id) { return os << PduIdText(id); } - -inline std::string AttributeIdText(const AttributeId& id) { - switch (id) { - CASE_RETURN_TEXT(AttributeId::SERVICE_RECORD_HANDLE); - CASE_RETURN_TEXT(AttributeId::SERVICE_CLASS_ID_LIST); - CASE_RETURN_TEXT(AttributeId::SERVICE_RECORD_STATE); - CASE_RETURN_TEXT(AttributeId::SERVICE_ID); - CASE_RETURN_TEXT(AttributeId::PROTOCOL_DESCRIPTOR_LIST); - CASE_RETURN_TEXT(AttributeId::BROWSE_GROUP_LIST); - CASE_RETURN_TEXT(AttributeId::LANGUAGE_BASE_ATTRIBUTE_ID_LIST); - CASE_RETURN_TEXT(AttributeId::SERVICE_INFO_TIME_TO_LIVE); - CASE_RETURN_TEXT(AttributeId::SERVICE_AVAILABILITY); - CASE_RETURN_TEXT(AttributeId::PROFILE_DESCRIPTOR_LIST); - CASE_RETURN_TEXT(AttributeId::DOCUMENTATION_URL); - CASE_RETURN_TEXT(AttributeId::CLIENT_EXECUTABLE_URL); - CASE_RETURN_TEXT(AttributeId::ICON_URL); - CASE_RETURN_TEXT(AttributeId::ADDITIONAL_PROTOCOL_DESCRIPTOR_LIST); - CASE_RETURN_TEXT(AttributeId::VERSION_NUMBER_LIST); - CASE_RETURN_TEXT(AttributeId::SERVICE_DATABASE_STATE); - default: - return fmt::format("Unknown AttributeId: 0x{:x}", (uint16_t)id); - } -} - -inline std::ostream& operator<<(std::ostream& os, const AttributeId& id) { - return os << AttributeIdText(id); -} - -inline std::string DataElementTypeText(const DataElementType& type) { - switch (type) { - CASE_RETURN_TEXT(DataElementType::NIL); - CASE_RETURN_TEXT(DataElementType::UNSIGNED_INT); - CASE_RETURN_TEXT(DataElementType::SIGNED_INT); - CASE_RETURN_TEXT(DataElementType::UUID); - CASE_RETURN_TEXT(DataElementType::STRING); - CASE_RETURN_TEXT(DataElementType::BOOLEAN); - CASE_RETURN_TEXT(DataElementType::DATA_ELEMENT_SEQUENCE); - CASE_RETURN_TEXT(DataElementType::DATA_ELEMENT_ALTERNATIVE); - CASE_RETURN_TEXT(DataElementType::URL); - default: - return fmt::format("Unknown DataElementType: 0x{:x}", (uint8_t)type); - } -} - -inline std::ostream& operator<<(std::ostream& os, const DataElementType& type) { - return os << DataElementTypeText(type); -} - -inline std::string DataElementSizeText(const DataElementSize& size) { - switch (size) { - CASE_RETURN_TEXT(DataElementSize::BYTE1); - CASE_RETURN_TEXT(DataElementSize::BYTE2); - CASE_RETURN_TEXT(DataElementSize::BYTE4); - CASE_RETURN_TEXT(DataElementSize::BYTE8); - CASE_RETURN_TEXT(DataElementSize::BYTE16); - CASE_RETURN_TEXT(DataElementSize::ADDITIONAL_8BIT); - CASE_RETURN_TEXT(DataElementSize::ADDITIONAL_16BIT); - CASE_RETURN_TEXT(DataElementSize::ADDITIONAL_32BIT); - default: - return fmt::format("Unknown DataElementSize: 0x{:x}", (uint8_t)size); - } -} - -inline std::ostream& operator<<(std::ostream& os, const DataElementSize& size) { - return os << DataElementSizeText(size); -} - -} // namespace sdp -} // namespace bluetooth - -namespace fmt { -template <> -struct formatter<bluetooth::sdp::PduId> : ostream_formatter {}; -template <> -struct formatter<bluetooth::sdp::AttributeId> : ostream_formatter {}; -template <> -struct formatter<bluetooth::sdp::DataElementType> : ostream_formatter {}; -template <> -struct formatter<bluetooth::sdp::DataElementSize> : ostream_formatter {}; -} // namespace fmt diff --git a/system/rust/src/core/ffi/module.cc b/system/rust/src/core/ffi/module.cc index 5e79d143fa..edd2b13b58 100644 --- a/system/rust/src/core/ffi/module.cc +++ b/system/rust/src/core/ffi/module.cc @@ -20,7 +20,7 @@ #include <hardware/bt_gatt.h> #include "btcore/include/module.h" -#include "os/log.h" + #ifndef TARGET_FLOSS #include "src/core/ffi.rs.h" #include "src/gatt/ffi.rs.h" diff --git a/system/rust/src/gatt/ffi/gatt_shim.cc b/system/rust/src/gatt/ffi/gatt_shim.cc index 3b17f83cda..442c5b5fa4 100644 --- a/system/rust/src/gatt/ffi/gatt_shim.cc +++ b/system/rust/src/gatt/ffi/gatt_shim.cc @@ -26,7 +26,6 @@ #include "include/hardware/bt_common_types.h" #include "include/hardware/bt_gatt_client.h" #include "include/hardware/bt_gatt_server.h" -#include "os/log.h" #include "rust/cxx.h" #include "stack/include/gatt_api.h" #include "types/bluetooth/uuid.h" diff --git a/system/stack/Android.bp b/system/stack/Android.bp index 5fec9d2cee..25cf3c5a5d 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -275,11 +275,11 @@ cc_library_static { "btm/security_event_parser.cc", "btu/btu_event.cc", "btu/btu_hcif.cc", + "connection_manager/connection_manager.cc", "eatt/eatt.cc", "gap/gap_ble.cc", "gap/gap_conn.cc", "gatt/att_protocol.cc", - "gatt/connection_manager.cc", "gatt/gatt_api.cc", "gatt/gatt_attr.cc", "gatt/gatt_auth.cc", @@ -540,6 +540,7 @@ cc_fuzz { ":TestMockStackAcl", ":TestMockStackArbiter", ":TestMockStackBtm", + ":TestMockStackConnMgr", ":TestMockStackHcic", ":TestMockStackL2cap", ":TestMockStackMetrics", @@ -1067,7 +1068,7 @@ cc_test { // Bluetooth stack connection multiplexing cc_test { - name: "net_test_gatt_conn_multiplexing", + name: "net_test_conn_multiplexing", defaults: [ "fluoride_defaults", "mts_defaults", @@ -1086,9 +1087,9 @@ cc_test { srcs: [ ":TestCommonMainHandler", ":TestMockStackBtmInterface", - "gatt/connection_manager.cc", + "connection_manager/connection_manager.cc", "test/common/mock_btm_api_layer.cc", - "test/gatt_connection_manager_test.cc", + "test/connection_manager_test.cc", ], shared_libs: [ "libcutils", @@ -1180,6 +1181,76 @@ cc_test { } cc_test { + name: "net_test_stack_avctp", + defaults: [ + "fluoride_defaults", + "mts_defaults", + ], + test_suites: ["general-tests"], + host_supported: true, + test_options: { + unit_test: true, + }, + include_dirs: [ + "external/libldac/inc", + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/gd", + "packages/modules/Bluetooth/system/stack/include", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestFakeOsi", + ":TestMockBta", + ":TestMockBtif", + ":TestMockDevice", + ":TestMockStackA2dp", + ":TestMockStackAcl", + ":TestMockStackL2cap", + "avct/avct_api.cc", + "avct/avct_bcb_act.cc", + "avct/avct_ccb.cc", + "avct/avct_l2c.cc", + "avct/avct_l2c_br.cc", + "avct/avct_lcb.cc", + "avct/avct_lcb_act.cc", + "test/stack_avctp_test.cc", + ], + shared_libs: [ + "libcrypto", + "libcutils", + "server_configurable_flags", + ], + static_libs: [ + "bluetooth_flags_c_lib_for_test", + "libaconfig_storage_read_api_cc", + "libbase", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_log", + "libbt-common", + "libchrome", + "libevent", + "libgmock", + "liblog", + "libosi", + "libprotobuf-cpp-lite", + "libstatslog_bt", + ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + }, + sanitize: { + address: true, + cfi: true, + misc_undefined: ["bounds"], + }, + header_libs: ["libbluetooth_headers"], +} + +cc_test { name: "net_test_stack_avdtp", defaults: [ "fluoride_defaults", @@ -1652,6 +1723,7 @@ cc_test { ":TestMockMainShimEntry", ":TestMockRustFfi", ":TestMockStackBtu", + ":TestMockStackConnMgr", ":TestMockStackGap", ":TestMockStackGatt", ":TestMockStackHcic", @@ -1972,9 +2044,9 @@ cc_test { ":TestMockStackSmp", "ais/ais_ble.cc", "arbiter/acl_arbiter.cc", + "connection_manager/connection_manager.cc", "eatt/eatt.cc", "gatt/att_protocol.cc", - "gatt/connection_manager.cc", "gatt/gatt_api.cc", "gatt/gatt_attr.cc", "gatt/gatt_auth.cc", @@ -2067,7 +2139,7 @@ cc_test { ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", - ":TestMockStackGatt", + ":TestMockStackConnMgr", ":TestMockStackHcic", ":TestMockStackSdp", ":TestMockStackSmp", @@ -2164,6 +2236,7 @@ cc_test { ":TestMockRustFfi", ":TestMockStackBtm", ":TestMockStackBtu", + ":TestMockStackConnMgr", ":TestMockStackGatt", ":TestMockStackHcic", ":TestMockStackL2cap", diff --git a/system/stack/BUILD.gn b/system/stack/BUILD.gn index c2b87b44a5..559aa1f366 100644 --- a/system/stack/BUILD.gn +++ b/system/stack/BUILD.gn @@ -125,7 +125,7 @@ source_set("stack") { "gap/gap_ble.cc", "gap/gap_conn.cc", "gatt/att_protocol.cc", - "gatt/connection_manager.cc", + "connection_manager/connection_manager.cc", "gatt/gatt_api.cc", "gatt/gatt_attr.cc", "gatt/gatt_auth.cc", diff --git a/system/stack/a2dp/a2dp_aac.cc b/system/stack/a2dp/a2dp_aac.cc index 1784e824c5..ca0dec4037 100644 --- a/system/stack/a2dp/a2dp_aac.cc +++ b/system/stack/a2dp/a2dp_aac.cc @@ -31,7 +31,6 @@ #include "a2dp_aac_decoder.h" #include "a2dp_aac_encoder.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/osi.h" #include "osi/include/properties.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_aac_decoder.cc b/system/stack/a2dp/a2dp_aac_decoder.cc index e1fb4f4929..fba7ea44cf 100644 --- a/system/stack/a2dp/a2dp_aac_decoder.cc +++ b/system/stack/a2dp/a2dp_aac_decoder.cc @@ -21,7 +21,6 @@ #include <aacdecoder_lib.h> #include <bluetooth/log.h> -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_aac_encoder.cc b/system/stack/a2dp/a2dp_aac_encoder.cc index d322d7f8cf..774fdd92ae 100644 --- a/system/stack/a2dp/a2dp_aac_encoder.cc +++ b/system/stack/a2dp/a2dp_aac_encoder.cc @@ -26,7 +26,6 @@ #include "a2dp_aac.h" #include "common/time_util.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_sbc_encoder.cc b/system/stack/a2dp/a2dp_sbc_encoder.cc index c0c923ec82..e5cb555262 100644 --- a/system/stack/a2dp/a2dp_sbc_encoder.cc +++ b/system/stack/a2dp/a2dp_sbc_encoder.cc @@ -25,11 +25,14 @@ #include <limits.h> #include <string.h> +#include <cinttypes> + #include "a2dp_sbc.h" #include "a2dp_sbc_up_sample.h" #include "common/time_util.h" #include "embdrv/sbc/encoder/include/sbc_encoder.h" #include "internal_include/bt_target.h" +#include "os/logging/log_adapter.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc index 969a06643d..7bb81bf244 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc @@ -28,7 +28,6 @@ #include "aptXbtenc.h" #include "common/time_util.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc index f6ed0c6cfa..cc59936638 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc @@ -32,7 +32,6 @@ #include "a2dp_vendor_aptx_hd_encoder.h" #include "btif/include/btif_av_co.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc index d6daf805a5..b6996d0108 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc @@ -28,7 +28,6 @@ #include "aptXHDbtenc.h" #include "common/time_util.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_vendor_ldac.cc b/system/stack/a2dp/a2dp_vendor_ldac.cc index b3ad871b31..8c1519eb65 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac.cc @@ -32,7 +32,6 @@ #include "a2dp_vendor_ldac_encoder.h" #include "btif/include/btif_av_co.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc index 4babdc79dc..4107e64e90 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc @@ -26,7 +26,6 @@ #include <string.h> #include "a2dp_vendor_ldac.h" -#include "os/log.h" #include "stack/include/bt_hdr.h" using namespace bluetooth; diff --git a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc index 7a616a038a..d89de9a550 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc @@ -31,7 +31,6 @@ #include "a2dp_vendor_ldac.h" #include "common/time_util.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/a2dp/a2dp_vendor_opus.cc b/system/stack/a2dp/a2dp_vendor_opus.cc index f6fb3c3e2d..fac881856f 100644 --- a/system/stack/a2dp/a2dp_vendor_opus.cc +++ b/system/stack/a2dp/a2dp_vendor_opus.cc @@ -31,7 +31,6 @@ #include "a2dp_vendor_opus_decoder.h" #include "a2dp_vendor_opus_encoder.h" #include "internal_include/bt_trace.h" -#include "os/log.h" #include "osi/include/osi.h" using namespace bluetooth; diff --git a/system/stack/a2dp/a2dp_vendor_opus_decoder.cc b/system/stack/a2dp/a2dp_vendor_opus_decoder.cc index 25658e60c0..bbbd3a2c3b 100644 --- a/system/stack/a2dp/a2dp_vendor_opus_decoder.cc +++ b/system/stack/a2dp/a2dp_vendor_opus_decoder.cc @@ -22,7 +22,6 @@ #include <opus.h> #include "a2dp_vendor_opus.h" -#include "os/log.h" #include "osi/include/allocator.h" using namespace bluetooth; diff --git a/system/stack/a2dp/a2dp_vendor_opus_encoder.cc b/system/stack/a2dp/a2dp_vendor_opus_encoder.cc index b59288c7c6..e7476c1028 100644 --- a/system/stack/a2dp/a2dp_vendor_opus_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_opus_encoder.cc @@ -26,7 +26,6 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_opus.h" #include "common/time_util.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/acl/ble_acl.cc b/system/stack/acl/ble_acl.cc index 1f5d5b580c..0606716f75 100644 --- a/system/stack/acl/ble_acl.cc +++ b/system/stack/acl/ble_acl.cc @@ -25,7 +25,7 @@ #include "stack/btm/btm_dev.h" #include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sec.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/include/acl_api.h" #include "stack/include/btm_ble_addr.h" #include "stack/include/btm_ble_privacy.h" diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc index 612fd9dc63..0c52e80bb6 100644 --- a/system/stack/acl/btm_acl.cc +++ b/system/stack/acl/btm_acl.cc @@ -76,6 +76,7 @@ #include "stack/include/l2cap_acl_interface.h" #include "stack/include/l2cdefs.h" #include "stack/include/main_thread.h" +#include "stack/l2cap/l2c_int.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -96,8 +97,6 @@ using bluetooth::legacy::hci::GetInterface; void BTM_update_version_info(const RawAddress& bd_addr, const remote_version_info& remote_version_info); -void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, const RawAddress& p_bda); - void BTM_db_reset(void); extern tBTM_CB btm_cb; diff --git a/system/stack/acl/btm_pm.cc b/system/stack/acl/btm_pm.cc index f77efd47b7..c34e776a1f 100644 --- a/system/stack/acl/btm_pm.cc +++ b/system/stack/acl/btm_pm.cc @@ -42,7 +42,6 @@ #include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" #include "main/shim/entry.h" -#include "os/log.h" #include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_int_types.h" #include "stack/include/bt_types.h" diff --git a/system/stack/avct/avct_api.cc b/system/stack/avct/avct_api.cc index 10c441d876..d4a6aab45e 100644 --- a/system/stack/avct/avct_api.cc +++ b/system/stack/avct/avct_api.cc @@ -28,11 +28,14 @@ #include <com_android_bluetooth_flags.h> #include <string.h> -#include "avct_int.h" #include "bta/include/bta_sec_api.h" #include "internal_include/bt_target.h" +#include "main/shim/dumpsys.h" #include "osi/include/allocator.h" +#include "stack/avct/avct_int.h" +#include "stack/include/avct_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/l2cap_interface.h" #include "types/raw_address.h" @@ -68,20 +71,20 @@ void AVCT_Register() { /* register PSM with L2CAP */ if (!stack::l2cap::get_interface().L2CA_RegisterWithSecurity( - AVCT_PSM, avct_l2c_appl, true /* enable_snoop */, nullptr, kAvrcMtu, 0, sec)) { - log::error("Unable to register with L2CAP AVCT profile psm:AVCT_PSM[0x0017]"); + BT_PSM_AVCTP, avct_l2c_appl, true /* enable_snoop */, nullptr, kAvrcMtu, 0, sec)) { + log::error("Unable to register with L2CAP AVCT profile psm:{}", bt_psm_text(BT_PSM_AVCTP)); } /* Include the browsing channel which uses eFCR */ - tL2CAP_ERTM_INFO ertm_info; - ertm_info.preferred_mode = L2CAP_FCR_ERTM_MODE; + tL2CAP_ERTM_INFO ertm_info = { + .preferred_mode = L2CAP_FCR_ERTM_MODE, + }; if (!stack::l2cap::get_interface().L2CA_RegisterWithSecurity( - AVCT_BR_PSM, avct_l2c_br_appl, true /*enable_snoop*/, &ertm_info, kAvrcBrMtu, + BT_PSM_AVCTP_BROWSE, avct_l2c_br_appl, true /*enable_snoop*/, &ertm_info, kAvrcBrMtu, AVCT_MIN_BROWSE_MTU, sec)) { - log::error( - "Unable to register with L2CAP AVCT_BR profile " - "psm:AVCT_BR_PSM[0x001b]"); + log::error("Unable to register with L2CAP AVCT_BROWSE profile psm:{}", + bt_psm_text(BT_PSM_AVCTP_BROWSE)); } } @@ -103,10 +106,17 @@ void AVCT_Deregister(void) { log::verbose("AVCT_Deregister"); /* deregister PSM with L2CAP */ - stack::l2cap::get_interface().L2CA_Deregister(AVCT_PSM); + stack::l2cap::get_interface().L2CA_Deregister(BT_PSM_AVCTP); /* deregister AVCT_BR_PSM with L2CAP */ - stack::l2cap::get_interface().L2CA_Deregister(AVCT_BR_PSM); + stack::l2cap::get_interface().L2CA_Deregister(BT_PSM_AVCTP_BROWSE); + + // Clean up AVCTP data structures + for (int i = 0; i < AVCT_NUM_LINKS; i++) { + osi_free(avct_cb.lcb[i].p_rx_msg); + fixed_queue_free(avct_cb.lcb[i].tx_q, nullptr); + osi_free_and_reset((void**)&(avct_cb.bcb[i].p_tx_msg)); + } } /******************************************************************************* @@ -131,7 +141,7 @@ uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, const RawAddress& pe tAVCT_CCB* p_ccb; tAVCT_LCB* p_lcb; - log::verbose("AVCT_CreateConn: {}, control:{}", p_cc->role, p_cc->control); + log::verbose("AVCT_CreateConn:{}, control:0x{:x}", avct_role_text(p_cc->role), p_cc->control); /* Allocate ccb; if no ccbs, return failure */ p_ccb = avct_ccb_alloc(p_cc); @@ -142,7 +152,7 @@ uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, const RawAddress& pe *p_handle = avct_ccb_to_idx(p_ccb); /* if initiator connection */ - if (p_cc->role == AVCT_INT) { + if (p_cc->role == AVCT_ROLE_INITIATOR) { /* find link; if none allocate a new one */ p_lcb = avct_lcb_by_bd(peer_addr); if (p_lcb == NULL) { @@ -162,9 +172,10 @@ uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, const RawAddress& pe if (result == AVCT_SUCCESS) { /* bind lcb to ccb */ p_ccb->p_lcb = p_lcb; - log::verbose("ch_state: {}", p_lcb->ch_state); - tAVCT_LCB_EVT avct_lcb_evt; - avct_lcb_evt.p_ccb = p_ccb; + log::verbose("ch_state:{}", avct_ch_state_text(p_lcb->ch_state)); + tAVCT_LCB_EVT avct_lcb_evt = { + .p_ccb = p_ccb, + }; avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, &avct_lcb_evt); } } @@ -226,13 +237,13 @@ uint16_t AVCT_RemoveConn(uint8_t handle) { * Returns AVCT_SUCCESS if successful, otherwise error. * ******************************************************************************/ -uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role) { +uint16_t AVCT_CreateBrowse(uint8_t handle, tAVCT_ROLE role) { uint16_t result = AVCT_SUCCESS; tAVCT_CCB* p_ccb; tAVCT_BCB* p_bcb; int index; - log::verbose("AVCT_CreateBrowse: {}", role); + log::verbose("AVCT_CreateBrowse: role:{}", avct_role_text(role)); /* map handle to ccb */ p_ccb = avct_ccb_by_idx(handle); @@ -246,7 +257,7 @@ uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role) { } /* if initiator connection */ - if (role == AVCT_INT) { + if (role == AVCT_ROLE_INITIATOR) { /* the link control block must exist before this function is called as INT. */ if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0)) { @@ -266,7 +277,7 @@ uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role) { /* bind bcb to ccb */ p_ccb->p_bcb = p_bcb; p_bcb->peer_addr = p_ccb->p_lcb->peer_addr; - log::verbose("ch_state: {}", p_bcb->ch_state); + log::verbose("Created BCB ch_state:{}", avct_ch_state_text(p_bcb->ch_state)); tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.p_ccb = p_ccb; avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, &avct_lcb_evt); @@ -390,7 +401,7 @@ uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg) { if (p_msg == NULL) { return AVCT_NO_RESOURCES; } - log::verbose("len: {} layer_specific: {}", p_msg->len, p_msg->layer_specific); + log::verbose("msg_len:{} msg_layer_specific:{}", p_msg->len, p_msg->layer_specific); /* map handle to ccb */ p_ccb = avct_ccb_by_idx(handle); @@ -432,3 +443,37 @@ uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg) { } return result; } + +#define DUMPSYS_TAG "stack::avct" + +void AVCT_Dumpsys(int fd) { + LOG_DUMPSYS_TITLE(fd, DUMPSYS_TAG); + for (int i = 0; i < AVCT_NUM_CONN; i++) { + const tAVCT_CCB& ccb = avct_cb.ccb[i]; + if (!ccb.allocated) { + continue; + } + LOG_DUMPSYS(fd, " Id:%2u profile_uuid:0x%04x role:%s control:0x%2x", i, ccb.cc.pid, + avct_role_text(ccb.cc.role).c_str(), ccb.cc.control); + if (ccb.p_lcb) { // tAVCT_LCB + LOG_DUMPSYS(fd, + " Link : peer:%s lcid:0x%04x sm_state:%-24s ch_state:%s conflict_lcid:0x%04x", + fmt::format("{}", ccb.p_lcb->peer_addr).c_str(), ccb.p_lcb->ch_lcid, + avct_sm_state_text(ccb.p_lcb->state).c_str(), + avct_ch_state_text(ccb.p_lcb->ch_state).c_str(), ccb.p_lcb->conflict_lcid); + } else { + LOG_DUMPSYS(fd, " Link : No link channel"); + } + + if (ccb.p_bcb) { // tAVCT_BCB + LOG_DUMPSYS(fd, + " Browse: peer:%s lcid:0x%04x sm_state:%-24s ch_state:%s conflict_lcid:0x%04x", + fmt::format("{}", ccb.p_bcb->peer_addr).c_str(), ccb.p_bcb->ch_lcid, + avct_sm_state_text(ccb.p_bcb->state).c_str(), + avct_ch_state_text(ccb.p_bcb->ch_state).c_str(), ccb.p_bcb->conflict_lcid); + } else { + LOG_DUMPSYS(fd, " Browse: No browse channel"); + } + } +} +#undef DUMPSYS_TAG diff --git a/system/stack/avct/avct_bcb_act.cc b/system/stack/avct/avct_bcb_act.cc index 75d54bbcee..37a5d20a97 100644 --- a/system/stack/avct/avct_bcb_act.cc +++ b/system/stack/avct/avct_bcb_act.cc @@ -25,26 +25,41 @@ * *****************************************************************************/ -#define LOG_TAG "bluetooth" - #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <string.h> -#include "avct_api.h" -#include "avct_int.h" #include "bta/include/bta_sec_api.h" #include "btif/include/btif_av.h" #include "internal_include/bt_target.h" #include "osi/include/allocator.h" -#include "osi/include/osi.h" #include "stack/avct/avct_defs.h" +#include "stack/avct/avct_int.h" +#include "stack/include/avct_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" #include "stack/include/l2cap_interface.h" using namespace bluetooth; +static void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_chnl_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_open_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_open_fail(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_close_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_close_cfm(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_cong_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_bind_conn(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_bind_fail(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_unbind_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_chk_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_dealloc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); +static void avct_bcb_free_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); + /* action function list */ const tAVCT_BCB_ACTION avct_bcb_action[] = { avct_bcb_chnl_open, /* AVCT_LCB_CHNL_OPEN */ @@ -92,7 +107,7 @@ static BT_HDR* avct_bcb_msg_asmbl(tAVCT_BCB* /* p_bcb */, BT_HDR* p_buf) { /* must be single packet - can not fragment */ if (pkt_type != AVCT_PKT_TYPE_SINGLE) { osi_free_and_reset((void**)&p_buf); - log::warn("Pkt type={} - fragmentation not allowed. drop it", pkt_type); + log::warn("Pkt type:{} - fragmentation not allowed. drop it", pkt_type); } return p_buf; } @@ -110,19 +125,15 @@ static BT_HDR* avct_bcb_msg_asmbl(tAVCT_BCB* /* p_bcb */, BT_HDR* p_buf) { void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* /* p_data */) { uint16_t result = AVCT_RESULT_FAIL; tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb); - tL2CAP_ERTM_INFO ertm_info; - - /* Set the FCR options: Browsing channel mandates ERTM */ - ertm_info.preferred_mode = L2CAP_FCR_ERTM_MODE; /* 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( - AVCT_BR_PSM, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + 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( - AVCT_BR_PSM, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE); + BT_PSM_AVCTP_BROWSE, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE); } if (p_bcb->ch_lcid == 0) { /* if connect req failed, send ourselves close event */ @@ -162,56 +173,68 @@ void avct_bcb_unbind_disc(tAVCT_BCB* /* p_bcb */, tAVCT_LCB_EVT* p_data) { * Returns Nothing. * ******************************************************************************/ +namespace { +bool is_valid_role_check(const tAVCT_CCB* p_ccb) { + return com::android::bluetooth::flags:: + associate_browse_l2cap_request_with_active_control_channel() + ? true + : p_ccb->cc.role == AVCT_ROLE_ACCEPTOR; +} +} // namespace + void avct_bcb_open_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; - tAVCT_CCB* p_ccb_bind = NULL; - bool bind = false; - tAVCT_UL_MSG ul_msg; + tAVCT_CCB* p_ccb_bind = nullptr; for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) { - /* if ccb allocated and */ - if (p_ccb->allocated) { - /* if bound to this bcb send connect confirm event */ - if (p_ccb->p_bcb == p_bcb) { - bind = true; - p_ccb_bind = p_ccb; - p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT, 0, - &p_ccb->p_lcb->peer_addr); - } + if (!p_ccb->allocated) { + continue; + } + + /* if ccb allocated and bound to this bcb send connect confirm event */ + if (p_ccb->p_bcb == p_bcb) { + p_ccb_bind = p_ccb; + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT, 0, + &p_ccb->p_lcb->peer_addr); + } else if ((p_ccb->p_bcb == NULL) && is_valid_role_check(p_ccb) && (p_ccb->p_lcb != NULL) && + p_bcb->peer_addr == p_ccb->p_lcb->peer_addr) { /* if unbound acceptor and lcb allocated and bd_addr are the same for bcb and lcb */ - else if ((p_ccb->p_bcb == NULL) && (p_ccb->cc.role == AVCT_ACP) && (p_ccb->p_lcb != NULL) && - p_bcb->peer_addr == p_ccb->p_lcb->peer_addr) { - /* bind bcb to ccb and send connect ind event */ - bind = true; - p_ccb_bind = p_ccb; - p_ccb->p_bcb = p_bcb; - p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT, 0, - &p_ccb->p_lcb->peer_addr); - } + /* bind bcb to ccb and send connect ind event */ + p_ccb_bind = p_ccb; + p_ccb->p_bcb = p_bcb; + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT, 0, + &p_ccb->p_lcb->peer_addr); } } /* if no ccbs bound to this lcb, disconnect */ - if (!bind) { + if (p_ccb_bind == nullptr) { + log::warn("Ignoring incoming browse request and closing channel from peer:{} lcid:0x{:04x}", + p_bcb->peer_addr, p_bcb->ch_lcid); avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data); return; } - if (!p_bcb->p_tx_msg || !p_ccb_bind) { + if (!p_bcb->p_tx_msg) { + log::warn("Received browse packet with no browse data peer:{} lcid:0x{:04x}", p_bcb->peer_addr, + p_bcb->ch_lcid); return; } - ul_msg.p_buf = p_bcb->p_tx_msg; - ul_msg.p_ccb = p_ccb_bind; - ul_msg.label = (uint8_t)(p_bcb->p_tx_msg->layer_specific & 0xFF); - ul_msg.cr = (uint8_t)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8); + tAVCT_UL_MSG ul_msg = { + .p_buf = p_bcb->p_tx_msg, + .p_ccb = p_ccb_bind, + .label = (uint8_t)(p_bcb->p_tx_msg->layer_specific & 0xFF), + .cr = (uint8_t)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8), + }; p_bcb->p_tx_msg->layer_specific = AVCT_DATA_BROWSE; p_bcb->p_tx_msg = NULL; /* send msg event to bcb */ - tAVCT_LCB_EVT avct_lcb_evt; - avct_lcb_evt.ul_msg = ul_msg; + tAVCT_LCB_EVT avct_lcb_evt = { + .ul_msg = ul_msg, + }; avct_bcb_event(p_bcb, AVCT_LCB_UL_MSG_EVT, &avct_lcb_evt); } @@ -253,7 +276,7 @@ void avct_bcb_close_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* /* p_data */) { for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) { if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) { - if (p_ccb->cc.role == AVCT_INT) { + if (p_ccb->cc.role == AVCT_ROLE_INITIATOR) { (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_CFM_EVT, 0, &p_lcb->peer_addr); } else { @@ -277,26 +300,19 @@ void avct_bcb_close_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* /* p_data */) { * ******************************************************************************/ void avct_bcb_close_cfm(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { - tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; - uint8_t event = 0; /* Whether BCB initiated channel close */ - bool ch_close = p_bcb->ch_close; - tAVCT_CTRL_CBACK* p_cback; - + const bool ch_close = p_bcb->ch_close; p_bcb->ch_close = false; p_bcb->allocated = 0; + + tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) { if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) { /* if this ccb initiated close send disconnect cfm otherwise ind */ - if (ch_close) { - event = AVCT_BROWSE_DISCONN_CFM_EVT; - } else { - event = AVCT_BROWSE_DISCONN_IND_EVT; - } - - p_cback = p_ccb->cc.p_ctrl_cback; - p_ccb->p_bcb = NULL; - if (p_ccb->p_lcb == NULL) { + uint8_t event = ch_close ? AVCT_BROWSE_DISCONN_CFM_EVT : AVCT_BROWSE_DISCONN_IND_EVT; + tAVCT_CTRL_CBACK* p_cback = p_ccb->cc.p_ctrl_cback; + p_ccb->p_bcb = nullptr; + if (p_ccb->p_lcb == nullptr) { avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL); } (*p_cback)(avct_ccb_to_idx(p_ccb), event, p_data->result, &p_bcb->peer_addr); @@ -386,11 +402,10 @@ void avct_bcb_bind_fail(tAVCT_BCB* /* p_bcb */, tAVCT_LCB_EVT* p_data) { ******************************************************************************/ void avct_bcb_cong_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; - uint8_t event; tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb); /* set event */ - event = (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT; + uint8_t event = (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT; /* send event to all ccbs on this lcb */ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) { @@ -424,7 +439,8 @@ void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { p_bcb->p_tx_msg->layer_specific = (p_data->ul_msg.cr << 8) + p_data->ul_msg.label; /* the channel is closed, opening or closing - open it again */ - log::verbose("ch_state: {}, allocated:{}->{}", p_bcb->ch_state, p_bcb->allocated, + log::verbose("ch_state:{} bcb_allocated:{} ccb_lcb_allocated:{}", + avct_ch_state_text(p_bcb->ch_state), p_bcb->allocated, p_data->ul_msg.p_ccb->p_lcb->allocated); p_bcb->allocated = p_data->ul_msg.p_ccb->p_lcb->allocated; avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT*)p_data->ul_msg.p_ccb); @@ -453,7 +469,7 @@ void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { /* initialize packet type and other stuff */ if (curr_msg_len > (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) { - log::error("msg len ({}) exceeds peer mtu({}-{})!!", curr_msg_len, p_bcb->peer_mtu, + log::error("msg_len:{} exceeds peer mtu:{} header-{})!!", curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE); osi_free_and_reset((void**)&p_data->ul_msg.p_buf); return; @@ -477,7 +493,7 @@ void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { /* send message to L2CAP */ if (stack::l2cap::get_interface().L2CA_DataWrite(p_bcb->ch_lcid, p_buf) != tL2CAP_DW_RESULT::SUCCESS) { - log::warn("Unable to write L2CAP data peer:{} cid:{}", p_bcb->peer_addr, p_bcb->ch_lcid); + log::warn("Unable to write L2CAP data peer:{} cid:0x{:04x}", p_bcb->peer_addr, p_bcb->ch_lcid); } } @@ -532,7 +548,7 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { } if (p_data->p_buf->len < AVCT_HDR_LEN_SINGLE) { - log::warn("Invalid AVCTP packet length {}: must be at least {}", p_data->p_buf->len, + log::warn("Invalid AVCTP packet length:{} must be at least:{}", p_data->p_buf->len, AVCT_HDR_LEN_SINGLE); osi_free_and_reset((void**)&p_data->p_buf); return; @@ -547,7 +563,7 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { /* check for invalid cr_ipid */ if (cr_ipid == AVCT_CR_IPID_INVALID) { - log::warn("Invalid cr_ipid {}", cr_ipid); + log::warn("Invalid cr_ipid:{}", cr_ipid); osi_free_and_reset((void**)&p_data->p_buf); return; } @@ -572,7 +588,7 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { } /* PID not found; drop message */ - log::warn("No ccb for PID={:x}", pid); + log::warn("No ccb for PID=0x{:x}", pid); osi_free_and_reset((void**)&p_data->p_buf); /* if command send reject */ @@ -586,7 +602,8 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { p_buf->layer_specific = AVCT_DATA_BROWSE; if (stack::l2cap::get_interface().L2CA_DataWrite(p_bcb->ch_lcid, p_buf) != tL2CAP_DW_RESULT::SUCCESS) { - log::warn("Unable to write L2CAP data peer:{} cid:{}", p_bcb->peer_addr, p_bcb->ch_lcid); + log::warn("Unable to write L2CAP data peer:{} cid:0x{:04x}", p_bcb->peer_addr, + p_bcb->ch_lcid); } } } @@ -604,13 +621,13 @@ void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) { void avct_bcb_dealloc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* /* p_data */) { tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; - log::verbose("{}", p_bcb->allocated); + log::verbose("BCB allocated:{}", p_bcb->allocated); for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) { /* if ccb allocated and */ if ((p_ccb->allocated) && (p_ccb->p_bcb == p_bcb)) { p_ccb->p_bcb = NULL; - log::verbose("used by ccb: {}", idx); + log::verbose("used by ccb idx:{}", idx); break; } } @@ -705,6 +722,6 @@ tAVCT_BCB* avct_bcb_by_lcid(uint16_t lcid) { } /* out of lcbs */ - log::warn("No bcb for lcid {:x}", lcid); - return NULL; + log::warn("No bcb for lcid 0x{:04x}", lcid); + return nullptr; } diff --git a/system/stack/avct/avct_ccb.cc b/system/stack/avct/avct_ccb.cc index 6210fd2fa7..6ffa34c3fb 100644 --- a/system/stack/avct/avct_ccb.cc +++ b/system/stack/avct/avct_ccb.cc @@ -23,8 +23,6 @@ * ******************************************************************************/ -#define LOG_TAG "avctp" - #include <bluetooth/log.h> #include <string.h> @@ -53,7 +51,7 @@ tAVCT_CCB* avct_ccb_alloc(tAVCT_CC* p_cc) { if (!p_ccb->allocated) { p_ccb->allocated = AVCT_ALOC_LCB; memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC)); - log::verbose("avct_ccb_alloc {}", i); + log::verbose("Allocated ccb idx:{}", i); break; } } @@ -80,7 +78,7 @@ tAVCT_CCB* avct_ccb_alloc(tAVCT_CC* p_cc) { void avct_ccb_dealloc(tAVCT_CCB* p_ccb, uint8_t event, uint16_t result, const RawAddress* bd_addr) { tAVCT_CTRL_CBACK* p_cback = p_ccb->cc.p_ctrl_cback; - log::verbose("avct_ccb_dealloc {}", avct_ccb_to_idx(p_ccb)); + log::verbose("Deallocating idx:{}", avct_ccb_to_idx(p_ccb)); if (p_ccb->p_bcb == NULL) { memset(p_ccb, 0, sizeof(tAVCT_CCB)); @@ -131,11 +129,11 @@ tAVCT_CCB* avct_ccb_by_idx(uint8_t idx) { /* verify ccb is allocated */ if (!p_ccb->allocated) { p_ccb = NULL; - log::warn("ccb {} not allocated", idx); + log::warn("ccb idx:{} not allocated", idx); } } else { p_ccb = NULL; - log::warn("No ccb for idx {}", idx); + log::warn("No ccb for idx:{}", idx); } return p_ccb; } diff --git a/system/stack/avct/avct_int.h b/system/stack/avct/avct_int.h index 0800523062..9efe7ad25e 100644 --- a/system/stack/avct/avct_int.h +++ b/system/stack/avct/avct_int.h @@ -24,7 +24,10 @@ #ifndef AVCT_INT_H #define AVCT_INT_H +#include <string> + #include "avct_api.h" +#include "include/macros.h" #include "internal_include/bt_target.h" #include "osi/include/fixed_queue.h" #include "stack/include/bt_hdr.h" @@ -48,10 +51,22 @@ enum { }; /* "states" used for L2CAP channel */ -#define AVCT_CH_IDLE 0 /* No connection */ -#define AVCT_CH_CONN 1 /* Waiting for connection confirm */ -#define AVCT_CH_CFG 2 /* Waiting for configuration complete */ -#define AVCT_CH_OPEN 3 /* Channel opened */ +enum tAVCT_CH { + AVCT_CH_IDLE = 0, /* No connection */ + AVCT_CH_CONN = 1, /* Waiting for connection confirm */ + AVCT_CH_CFG = 2, /* Waiting for configuration complete */ + AVCT_CH_OPEN = 3, /* Channel opened */ +}; + +inline std::string avct_ch_state_text(const int& state) { + switch (state) { + CASE_RETURN_STRING(AVCT_CH_IDLE); + CASE_RETURN_STRING(AVCT_CH_CONN); + CASE_RETURN_STRING(AVCT_CH_CFG); + CASE_RETURN_STRING(AVCT_CH_OPEN); + } + RETURN_UNKNOWN_TYPE_STRING(int, state); +} /* "no event" indicator used by ccb dealloc */ #define AVCT_NO_EVT 0xFF @@ -59,16 +74,6 @@ enum { /***************************************************************************** * data types ****************************************************************************/ -/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */ -typedef struct { - uint16_t peer_mtu; /* peer l2c mtu */ - uint16_t ch_result; /* L2CAP connection result value */ - uint16_t ch_lcid; /* L2CAP channel LCID */ - uint8_t allocated; /* 0, not allocated. index+1, otherwise. */ - uint8_t state; /* The state machine state */ - uint8_t ch_state; /* L2CAP channel state */ -} tAVCT_SCB; - /* link control block type */ typedef struct { uint16_t peer_mtu; /* peer l2c mtu */ @@ -89,7 +94,7 @@ typedef struct { uint16_t peer_mtu; /* peer l2c mtu */ uint16_t ch_result; /* L2CAP connection result value */ uint16_t ch_lcid; /* L2CAP channel LCID */ - uint8_t allocated; /* 0, not allocated. index+1, otherwise. */ + uint8_t allocated; // 0: no link allocated. otherwise link index+1 uint8_t state; /* The state machine state */ uint8_t ch_state; /* L2CAP channel state */ uint16_t conflict_lcid; /* L2CAP channel LCID */ @@ -173,23 +178,6 @@ void avct_lcb_free_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data); /* BCB action functions */ typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_unbind_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_open_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_open_fail(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_close_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_close_cfm(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_bind_conn(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_chk_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_chnl_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_bind_fail(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_cong_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); -void avct_bcb_free_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); - -void avct_bcb_dealloc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data); extern const tAVCT_BCB_ACTION avct_bcb_action[]; extern const uint8_t avct_lcb_pkt_type_len[]; @@ -203,6 +191,8 @@ tAVCT_CCB* avct_ccb_by_idx(uint8_t idx); extern bool avct_msg_ind_for_src_sink_coexist(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data, uint8_t label, uint8_t cr_ipid, uint16_t pid); +std::string avct_sm_state_text(const int& state); + /***************************************************************************** * global data ****************************************************************************/ diff --git a/system/stack/avct/avct_l2c.cc b/system/stack/avct/avct_l2c.cc index adca67c851..e3001eeaa2 100644 --- a/system/stack/avct/avct_l2c.cc +++ b/system/stack/avct/avct_l2c.cc @@ -21,8 +21,6 @@ * This AVCTP module interfaces to L2CAP * ******************************************************************************/ -#define LOG_TAG "avctp" - #include <bluetooth/log.h> #include "avct_api.h" @@ -32,18 +30,20 @@ #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2cap_interface.h" +#include "stack/include/l2cdefs.h" #include "types/raw_address.h" using namespace bluetooth; /* callback function declarations */ -void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t psm, uint8_t id); -void avct_l2c_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result); -void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t result, tL2CAP_CFG_INFO* p_cfg); -void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); -void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed); -void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested); -void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf); +static void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t psm, + uint8_t id); +static void avct_l2c_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result); +static void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t result, tL2CAP_CFG_INFO* p_cfg); +static void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); +static void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed); +static void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested); +static void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf); static void avct_on_l2cap_error(uint16_t lcid, uint16_t result); /* L2CAP callback function structure */ @@ -103,21 +103,19 @@ static bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) { ******************************************************************************/ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t /* psm */, uint8_t /* id */) { - tAVCT_LCB* p_lcb; tL2CAP_CONN result = tL2CAP_CONN::L2CAP_CONN_OK; /* do we already have a channel for this peer? */ - p_lcb = avct_lcb_by_bd(bd_addr); - if (p_lcb == NULL) { + tAVCT_LCB* p_lcb = avct_lcb_by_bd(bd_addr); + if (p_lcb == nullptr) { /* no, allocate lcb */ p_lcb = avct_lcb_alloc(bd_addr); - if (p_lcb == NULL) { + if (p_lcb == nullptr) { /* no ccb available, reject L2CAP connection */ result = tL2CAP_CONN::L2CAP_CONN_NO_RESOURCES; } - } - /* else we already have a channel for this peer */ - else { + } else { + /* else we already have a channel for this peer */ if (!avct_l2c_is_passive(p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) { /* this LCB included CT role - reject */ result = tL2CAP_CONN::L2CAP_CONN_NO_RESOURCES; @@ -125,19 +123,8 @@ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16 /* TG role only - accept the connection from CT. move the channel ID to * the conflict list */ p_lcb->conflict_lcid = p_lcb->ch_lcid; - log::verbose("avct_l2c_connect_ind_cback conflict_lcid:0x{:x}", p_lcb->conflict_lcid); - } - } - - if (p_lcb) { - log::verbose("avct_l2c_connect_ind_cback: 0x{:x}, res: {}, ch_state: {}", lcid, result, - p_lcb->ch_state); - } - - /* If we reject the connection, send DisconnectReq */ - if (result != tL2CAP_CONN::L2CAP_CONN_OK) { - if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { - log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}", bd_addr, lcid); + log::verbose("Accept connection from controller lcid:0x{:04x} conflict_lcid:0x{:04x}", lcid, + p_lcb->conflict_lcid); } } @@ -146,10 +133,13 @@ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16 if (btif_av_src_sink_coexist_enabled()) { tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { - if (p_ccb && p_ccb->allocated && (p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP)) { + if (p_ccb && p_ccb->allocated && (p_ccb->p_lcb == NULL) && + (p_ccb->cc.role == AVCT_ROLE_ACCEPTOR)) { p_ccb->p_lcb = p_lcb; - log::verbose("ACP bind {} ccb to lcb, alloc {}, lcb {}, role {}, pid 0x{:x}", i, - p_ccb->allocated, fmt::ptr(p_ccb->p_lcb), p_ccb->cc.role, p_ccb->cc.pid); + log::verbose( + "Source and sink coexistance enabled acceptor bind ccb to lcb idx:{} " + "allocated:{} role {} pid 0x{:x}", + i, p_ccb->allocated, avct_role_text(p_ccb->cc.role), p_ccb->cc.pid); } } } @@ -158,10 +148,18 @@ void avct_l2c_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16 /* transition to configuration state */ p_lcb->ch_state = AVCT_CH_CFG; - } - if (p_lcb) { - log::verbose("ch_state cni: {}", p_lcb->ch_state); + log::debug("Received remote connection request peer:{} lcid:0x{:04x} ch_state:{}", bd_addr, + lcid, avct_ch_state_text(p_lcb->ch_state)); + } else { + /* If we reject the connection, send DisconnectReq */ + if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { + log::warn("Unable to send L2CAP disconnect request peer:{} lcid:0x{:04x}", bd_addr, lcid); + } + log::info( + "Ignoring remote connection request no link or no resources peer:{} lcid:0x{:04x} " + "lcb_exists:{}", + bd_addr, lcid, p_lcb != nullptr); } } @@ -186,7 +184,8 @@ static void avct_on_l2cap_error(uint16_t lcid, uint16_t result) { /* Send L2CAP disconnect req */ if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { - log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}", p_lcb->peer_addr, lcid); + log::warn("Unable to send L2CAP disconnect request peer:{} lcid:0x{:04x}", p_lcb->peer_addr, + lcid); } } } @@ -207,36 +206,34 @@ void avct_l2c_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result) { /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { - log::verbose( - "avct_l2c_connect_cfm_cback lcid:0x{:x} result: {} ch_state: {}, " - "conflict_lcid:0x{:x}", - lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid); + log::verbose("lcid:0x{:04x} result:{} ch_state:{} conflict_lcid:0x{:04x}", lcid, result, + avct_ch_state_text(p_lcb->ch_state), p_lcb->conflict_lcid); /* if in correct state */ if (p_lcb->ch_state == AVCT_CH_CONN) { /* if result successful */ if (result == tL2CAP_CONN::L2CAP_CONN_OK) { /* set channel state */ p_lcb->ch_state = AVCT_CH_CFG; - } - /* else failure */ - else { - log::error("invoked with non OK status"); + } else { + /* else failure */ + log::error("invoked with non OK status lcid:0x{:04x} result:{}", lcid, + l2cap_result_code_text(result)); } } else if (p_lcb->conflict_lcid == lcid) { /* we must be in AVCT_CH_CFG state for the ch_lcid channel */ - log::verbose("avct_l2c_connect_cfm_cback ch_state: {}, conflict_lcid:0x{:x}", p_lcb->ch_state, + log::verbose("ch_state:{} conflict_lcid:0x{:04x}", avct_ch_state_text(p_lcb->ch_state), p_lcb->conflict_lcid); if (result == tL2CAP_CONN::L2CAP_CONN_OK) { /* just in case the peer also accepts our connection - Send L2CAP * disconnect req */ if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { - log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}", p_lcb->peer_addr, - lcid); + log::warn("Unable to send L2CAP disconnect request peer:{} cid:0x{:04x}", + p_lcb->peer_addr, lcid); } } p_lcb->conflict_lcid = 0; } - log::verbose("ch_state cnc: {}", p_lcb->ch_state); + log::verbose("ch_state:{}", avct_ch_state_text(p_lcb->ch_state)); } } @@ -250,22 +247,29 @@ void avct_l2c_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result) { * Returns void * ******************************************************************************/ -void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t /* initiator */, tL2CAP_CFG_INFO* p_cfg) { +void avct_l2c_config_cfm_cback(uint16_t lcid, uint16_t is_initiator_local, tL2CAP_CFG_INFO* p_cfg) { avct_l2c_config_ind_cback(lcid, p_cfg); - tAVCT_LCB* p_lcb; - /* look up lcb for this channel */ - p_lcb = avct_lcb_by_lcid(lcid); - if (p_lcb != NULL) { - log::verbose("avct_l2c_config_cfm_cback: 0x{:x}, ch_state: {},", lcid, p_lcb->ch_state); - /* if in correct state */ - if (p_lcb->ch_state == AVCT_CH_CFG) { - p_lcb->ch_state = AVCT_CH_OPEN; - avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); - } - log::verbose("ch_state cfc: {}", p_lcb->ch_state); + tAVCT_LCB* p_lcb = avct_lcb_by_lcid(lcid); + if (p_lcb == nullptr) { + log::warn("Received config confirm for unknown peer lcid::0x{:04x} is_initiator_local:{}", lcid, + is_initiator_local); + return; + } + + /* if in correct state */ + if (p_lcb->ch_state == AVCT_CH_CFG) { + p_lcb->ch_state = AVCT_CH_OPEN; + avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); + } else { + log::warn( + "Received config confirm in wrong state lcid:0x{:04x} ch_state:{} " + "is_initiator_local:{}", + lcid, avct_ch_state_text(p_lcb->ch_state), is_initiator_local); } + log::verbose("ch_state lcid:0x{:04x} ch_state:{} is_initiator_local:{}", lcid, + avct_ch_state_text(p_lcb->ch_state), is_initiator_local); } /******************************************************************************* @@ -284,7 +288,8 @@ void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { /* look up lcb for this channel */ p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { - log::verbose("avct_l2c_config_ind_cback: 0x{:x}, ch_state: {}", lcid, p_lcb->ch_state); + log::verbose("avct_l2c_config_ind_cback: 0x{:04x}, ch_state:{}", lcid, + avct_ch_state_text(p_lcb->ch_state)); /* store the mtu in tbl */ if (p_cfg->mtu_present) { p_lcb->peer_mtu = p_cfg->mtu; @@ -339,7 +344,7 @@ void avct_l2c_disconnect(uint16_t lcid, uint16_t result) { tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.result = res; avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); - log::verbose("ch_state dc: {}", p_lcb->ch_state); + log::verbose("ch_state:{}", p_lcb->ch_state); } } @@ -377,15 +382,13 @@ void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) { * ******************************************************************************/ void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) { - tAVCT_LCB* p_lcb; - - log::verbose("avct_l2c_data_ind_cback: 0x{:x}", lcid); + log::verbose("lcid: 0x{:02x}", lcid); /* look up lcb for this channel */ - p_lcb = avct_lcb_by_lcid(lcid); + tAVCT_LCB* p_lcb = avct_lcb_by_lcid(lcid); if (p_lcb != NULL) { avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf); - } else /* prevent buffer leak */ - { + } else { + /* prevent buffer leak */ log::warn("ERROR -> avct_l2c_data_ind_cback drop buffer"); osi_free(p_buf); } diff --git a/system/stack/avct/avct_l2c_br.cc b/system/stack/avct/avct_l2c_br.cc index 4c5ccc503b..3f76e0b76f 100644 --- a/system/stack/avct/avct_l2c_br.cc +++ b/system/stack/avct/avct_l2c_br.cc @@ -24,30 +24,29 @@ * *****************************************************************************/ -#define LOG_TAG "avctp" - #include <bluetooth/log.h> -#include "avct_api.h" -#include "avct_int.h" #include "internal_include/bt_target.h" #include "osi/include/allocator.h" +#include "stack/avct/avct_int.h" +#include "stack/include/avct_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2cap_interface.h" +#include "stack/include/l2cdefs.h" #include "types/raw_address.h" using namespace bluetooth; /* callback function declarations */ -void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t psm, - uint8_t id); -void avct_l2c_br_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result); -void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t result, tL2CAP_CFG_INFO* p_cfg); -void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); -void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed); -void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested); -void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf); -void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result); +static void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t psm, + uint8_t id); +static void avct_l2c_br_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result); +static void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t result, tL2CAP_CFG_INFO* p_cfg); +static void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg); +static void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed); +static void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested); +static void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf); +static void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result); /* L2CAP callback function structure */ const tL2CAP_APPL_INFO avct_l2c_br_appl = {avct_l2c_br_connect_ind_cback, @@ -77,9 +76,8 @@ const tL2CAP_APPL_INFO avct_l2c_br_appl = {avct_l2c_br_connect_ind_cback, ******************************************************************************/ static bool avct_l2c_br_is_passive(tAVCT_BCB* p_bcb) { bool is_passive = false; - tAVCT_LCB* p_lcb; tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; - p_lcb = avct_lcb_by_bcb(p_bcb); + tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb); int i; for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { @@ -106,12 +104,10 @@ static bool avct_l2c_br_is_passive(tAVCT_BCB* p_bcb) { ******************************************************************************/ void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uint16_t /* psm */, uint8_t /* id */) { - tAVCT_LCB* p_lcb; tL2CAP_CONN result = tL2CAP_CONN::L2CAP_CONN_NO_RESOURCES; - tAVCT_BCB* p_bcb; - tL2CAP_ERTM_INFO ertm_info; + tAVCT_BCB* p_bcb{nullptr}; - p_lcb = avct_lcb_by_bd(bd_addr); + tAVCT_LCB* p_lcb = avct_lcb_by_bd(bd_addr); if (p_lcb != NULL) { /* control channel exists */ p_bcb = avct_bcb_by_lcb(p_lcb); @@ -136,26 +132,20 @@ void avct_l2c_br_connect_ind_cback(const RawAddress& bd_addr, uint16_t lcid, uin } } } - /* else no control channel yet, reject */ - - /* Set the FCR options: Browsing channel mandates ERTM */ - ertm_info.preferred_mode = L2CAP_FCR_ERTM_MODE; - - /* If we reject the connection, send DisconnectReq */ - if (result != tL2CAP_CONN::L2CAP_CONN_OK) { - log::verbose("Connection rejected to lcid:0x{:x}", lcid); - if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { - log::warn("Unable to send L2CAP disconnect request cid:{}", lcid); - } - } /* if result ok, proceed with connection */ if (result == tL2CAP_CONN::L2CAP_CONN_OK) { /* store LCID */ p_bcb->ch_lcid = lcid; - /* transition to configuration state */ p_bcb->ch_state = AVCT_CH_CFG; + } else { + /* else no control channel yet, reject */ + /* If we reject the connection, send DisconnectReq */ + log::verbose("Connection rejected to lcid:0x{:x}", lcid); + if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { + log::warn("Unable to send L2CAP disconnect request cid:0x{:04x}", lcid); + } } } @@ -174,7 +164,7 @@ void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result) { p_bcb->ch_result = result; /* Send L2CAP disconnect req */ - avct_l2c_br_disconnect(lcid, 0); + avct_l2c_br_disconnect(lcid, 0 /* is_ack_needed */); } /******************************************************************************* @@ -188,24 +178,23 @@ void avct_br_on_l2cap_error(uint16_t lcid, uint16_t result) { * ******************************************************************************/ void avct_l2c_br_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result) { - tAVCT_BCB* p_bcb; - /* look up bcb for this channel */ - p_bcb = avct_bcb_by_lcid(lcid); - - if (p_bcb == NULL) { + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == nullptr) { + log::warn( + "Received browse connect confirm callback without a browse control channel " + "lcid:0x{:02x} status:{}", + lcid, l2cap_result_code_text(result)); return; } - /* if in correct state */ if (p_bcb->ch_state == AVCT_CH_CONN) { /* if result successful */ if (result == tL2CAP_CONN::L2CAP_CONN_OK) { /* set channel state */ p_bcb->ch_state = AVCT_CH_CFG; - } - /* else failure */ - else { - log::error("Invoked with non OK status"); + } else { + log::error("Invoked with non OK lcid:0x{:04x} state:{} status:{}", lcid, + avct_ch_state_text(p_bcb->ch_state), l2cap_result_code_text(result)); } } else if (p_bcb->conflict_lcid == lcid) { /* we must be in AVCT_CH_CFG state for the ch_lcid channel */ @@ -214,8 +203,12 @@ void avct_l2c_br_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result) { * disconnect req */ log::verbose("Disconnect conflict_lcid:0x{:x}", p_bcb->conflict_lcid); if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { - log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}", p_bcb->peer_addr, lcid); + log::warn("Unable to send L2CAP disconnect request peer:{} lcid:0x{:04x}", p_bcb->peer_addr, + lcid); } + } else { + log::error("Invoked with failure peer:{} lcid:0x{:04x} conflict_lcid:0x{:04x} status:{}", + p_bcb->peer_addr, lcid, p_bcb->conflict_lcid, l2cap_result_code_text(result)); } p_bcb->conflict_lcid = 0; } @@ -231,19 +224,21 @@ void avct_l2c_br_connect_cfm_cback(uint16_t lcid, tL2CAP_CONN result) { * Returns void * ******************************************************************************/ -void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t /* initiator */, tL2CAP_CFG_INFO* p_cfg) { +void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t initiator, tL2CAP_CFG_INFO* p_cfg) { + log::verbose("lcid:0x{:04x} initiator:{}", lcid, initiator); avct_l2c_br_config_ind_cback(lcid, p_cfg); - tAVCT_BCB* p_lcb; - - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CFG)) { + /* look up bcb for this channel */ + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if ((p_bcb == NULL) || (p_bcb->ch_state != AVCT_CH_CFG)) { + log::warn( + "Got config confirm callback with no browse channel or browse channel not in " + "configuration state"); return; } - p_lcb->ch_state = AVCT_CH_OPEN; - avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); + p_bcb->ch_state = AVCT_CH_OPEN; + avct_bcb_event(p_bcb, AVCT_LCB_LL_OPEN_EVT, NULL); } /******************************************************************************* @@ -257,26 +252,27 @@ void avct_l2c_br_config_cfm_cback(uint16_t lcid, uint16_t /* initiator */, tL2CA * ******************************************************************************/ void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { - tAVCT_BCB* p_lcb; - uint16_t max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE; + log::verbose("lcid:0x{:04x}", lcid); + const uint16_t max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE; - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if (p_lcb == NULL) { + /* look up bcb for this channel */ + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == NULL) { + log::warn("Unable to find browse control block lcid:0x{:02x}", lcid); return; } /* store the mtu in tbl */ - p_lcb->peer_mtu = L2CAP_DEFAULT_MTU; + p_bcb->peer_mtu = L2CAP_DEFAULT_MTU; if (p_cfg->mtu_present) { - p_lcb->peer_mtu = p_cfg->mtu; + p_bcb->peer_mtu = p_cfg->mtu; } - if (p_lcb->peer_mtu > max_mtu) { - p_lcb->peer_mtu = max_mtu; + if (p_bcb->peer_mtu > max_mtu) { + p_bcb->peer_mtu = max_mtu; } - log::verbose("peer_mtu:{} use:{}", p_lcb->peer_mtu, max_mtu); + log::verbose("peer_mtu:{} max_mtu:{}", p_bcb->peer_mtu, max_mtu); } /******************************************************************************* @@ -290,41 +286,37 @@ void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { * ******************************************************************************/ void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool /* ack_needed */) { - tAVCT_BCB* p_lcb; uint16_t result = AVCT_RESULT_FAIL; - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if (p_lcb == NULL) { + /* look up bcb for this channel */ + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == NULL) { return; } tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.result = result; - avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); + avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); } void avct_l2c_br_disconnect(uint16_t lcid, uint16_t result) { if (!stack::l2cap::get_interface().L2CA_DisconnectReq(lcid)) { - log::warn("Unable to send L2CAP disconnect request cid:{}", lcid); + log::warn("Unable to send L2CAP disconnect request cid:0x{:04x}", lcid); } - tAVCT_BCB* p_lcb; - uint16_t res; - - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if (p_lcb == NULL) { + /* look up bcb for this channel */ + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == NULL) { return; } /* result value may be previously stored */ - res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result; - p_lcb->ch_result = 0; + uint16_t res = (p_bcb->ch_result != 0) ? p_bcb->ch_result : result; + p_bcb->ch_result = 0; tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.result = res; - avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); + avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt); } /******************************************************************************* @@ -338,17 +330,15 @@ void avct_l2c_br_disconnect(uint16_t lcid, uint16_t result) { * ******************************************************************************/ void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested) { - tAVCT_BCB* p_lcb; - - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if (p_lcb == NULL) { + /* look up bcb for this channel */ + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == NULL) { return; } tAVCT_LCB_EVT avct_lcb_evt; avct_lcb_evt.cong = is_congested; - avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, &avct_lcb_evt); + avct_bcb_event(p_bcb, AVCT_LCB_LL_CONG_EVT, &avct_lcb_evt); } /******************************************************************************* @@ -362,17 +352,15 @@ void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested) { * ******************************************************************************/ void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) { - tAVCT_BCB* p_lcb; - tAVCT_LCB_EVT evt_data; - - /* look up lcb for this channel */ - p_lcb = avct_bcb_by_lcid(lcid); - if (p_lcb == NULL) { + /* look up bcb for this channel */ + tAVCT_BCB* p_bcb = avct_bcb_by_lcid(lcid); + if (p_bcb == NULL) { /* prevent buffer leak */ osi_free(p_buf); return; } + tAVCT_LCB_EVT evt_data{}; evt_data.p_buf = p_buf; - avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, &evt_data); + avct_bcb_event(p_bcb, AVCT_LCB_LL_MSG_EVT, &evt_data); } diff --git a/system/stack/avct/avct_lcb.cc b/system/stack/avct/avct_lcb.cc index c8e12c4f08..26d4a73160 100644 --- a/system/stack/avct/avct_lcb.cc +++ b/system/stack/avct/avct_lcb.cc @@ -23,18 +23,15 @@ * ******************************************************************************/ -#define LOG_TAG "avctp" - #include <bluetooth/log.h> #include <string.h> #include "avct_api.h" #include "avct_int.h" #include "device/include/device_iot_config.h" +#include "include/macros.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" -#include "osi/include/osi.h" #include "types/raw_address.h" using namespace bluetooth; @@ -55,6 +52,16 @@ const char* const avct_lcb_evt_str[] = {"UL_BIND_EVT", "UL_UNBIND_EVT", "UL_MS /* lcb state machine states */ enum { AVCT_LCB_IDLE_ST, AVCT_LCB_OPENING_ST, AVCT_LCB_OPEN_ST, AVCT_LCB_CLOSING_ST }; +std::string avct_sm_state_text(const int& state) { + switch (state) { + CASE_RETURN_STRING(AVCT_LCB_IDLE_ST); + CASE_RETURN_STRING(AVCT_LCB_OPENING_ST); + CASE_RETURN_STRING(AVCT_LCB_OPEN_ST); + CASE_RETURN_STRING(AVCT_LCB_CLOSING_ST); + } + RETURN_UNKNOWN_TYPE_STRING(int, state); +} + /* state machine action enumeration list */ enum { AVCT_LCB_CHNL_OPEN, @@ -163,7 +170,7 @@ void avct_lcb_event(tAVCT_LCB* p_lcb, uint8_t event, tAVCT_LCB_EVT* p_data) { uint8_t action; int i; - log::verbose("LCB lcb={} event={} state={}", p_lcb->allocated, avct_lcb_evt_str[event], + log::verbose("LCB lcb_allocated={} event={} state={}", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]); /* look up the state table for the current state */ @@ -198,22 +205,18 @@ void avct_lcb_event(tAVCT_LCB* p_lcb, uint8_t event, tAVCT_LCB_EVT* p_data) { * ******************************************************************************/ void avct_bcb_event(tAVCT_BCB* p_bcb, uint8_t event, tAVCT_LCB_EVT* p_data) { - tAVCT_LCB_ST_TBL state_table; - uint8_t action; - int i; - - log::verbose("BCB lcb={} event={} state={}", p_bcb->allocated, avct_lcb_evt_str[event], - avct_lcb_st_str[p_bcb->state]); + log::info("BCB bcb_allocated={} event={} state={}", p_bcb->allocated, avct_lcb_evt_str[event], + avct_lcb_st_str[p_bcb->state]); /* look up the state table for the current state */ - state_table = avct_lcb_st_tbl[p_bcb->state]; + tAVCT_LCB_ST_TBL state_table = avct_lcb_st_tbl[p_bcb->state]; /* set next state */ p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE]; /* execute action functions */ - for (i = 0; i < AVCT_LCB_ACTIONS; i++) { - action = state_table[event][i]; + for (int i = 0; i < AVCT_LCB_ACTIONS; i++) { + uint8_t action = state_table[event][i]; if (action != AVCT_LCB_IGNORE) { (*avct_bcb_action[action])(p_bcb, p_data); } else { @@ -247,7 +250,7 @@ tAVCT_LCB* avct_lcb_by_bd(const RawAddress& bd_addr) { /* if no lcb found */ p_lcb = NULL; - log::verbose("No lcb for addr {}", bd_addr); + log::verbose("No lcb for addr:{}", bd_addr); } return p_lcb; } @@ -270,7 +273,7 @@ tAVCT_LCB* avct_lcb_alloc(const RawAddress& bd_addr) { if (!p_lcb->allocated) { p_lcb->allocated = (uint8_t)(i + 1); p_lcb->peer_addr = bd_addr; - log::verbose("avct_lcb_alloc {}", p_lcb->allocated); + log::verbose("lcb_allocated:{}", p_lcb->allocated); p_lcb->tx_q = fixed_queue_new(SIZE_MAX); p_lcb->peer_mtu = L2CAP_LE_MIN_MTU; break; @@ -296,14 +299,14 @@ tAVCT_LCB* avct_lcb_alloc(const RawAddress& bd_addr) { * ******************************************************************************/ void avct_lcb_dealloc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* /* p_data */) { - log::verbose("allocated: {}", p_lcb->allocated); + log::verbose("lcb_allocated:{}", p_lcb->allocated); // Check if the LCB is still referenced tAVCT_CCB* p_ccb = &avct_cb.ccb[0]; for (size_t i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { if (p_ccb->allocated && p_ccb->p_lcb == p_lcb) { - log::verbose("LCB in use; lcb index: {}", i); + log::verbose("LCB in use; lcb index:{}", i); return; } } @@ -383,8 +386,7 @@ bool avct_lcb_last_ccb(tAVCT_LCB* p_lcb, tAVCT_CCB* p_ccb_last) { log::warn("avct_lcb_last_ccb"); for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { - log::warn("{:x}: aloc:{}, lcb:0x{}/0x{}, ccb:0x{}/0x{}", i, p_ccb->allocated, - fmt::ptr(p_ccb->p_lcb), fmt::ptr(p_lcb), fmt::ptr(p_ccb), fmt::ptr(p_ccb_last)); + log::warn("index:{} allocated:{}, ", i, p_ccb->allocated); if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last)) { return false; } diff --git a/system/stack/avct/avct_lcb_act.cc b/system/stack/avct/avct_lcb_act.cc index e06bf57634..986bce7d34 100644 --- a/system/stack/avct/avct_lcb_act.cc +++ b/system/stack/avct/avct_lcb_act.cc @@ -33,7 +33,9 @@ #include "internal_include/bt_target.h" #include "osi/include/allocator.h" #include "stack/avct/avct_defs.h" +#include "stack/include/avct_api.h" #include "stack/include/bt_hdr.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" #include "stack/include/l2cap_interface.h" @@ -190,10 +192,10 @@ void avct_lcb_chnl_open(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* /* p_data */) { 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( - AVCT_PSM, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + BT_PSM_AVCTP, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); } else { p_lcb->ch_lcid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity( - AVCT_PSM, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE); + BT_PSM_AVCTP, p_lcb->peer_addr, BTA_SEC_AUTHENTICATE); } if (p_lcb->ch_lcid == 0) { /* if connect req failed, send ourselves close event */ @@ -239,7 +241,7 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { bool is_originater = false; for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { - if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && p_ccb->cc.role == AVCT_INT) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && p_ccb->cc.role == AVCT_ROLE_INITIATOR) { log::verbose("find int handle {}", i); is_originater = true; } @@ -250,16 +252,16 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { /* if ccb allocated and */ /** M: to avoid avctp collision, make sure the collision can be checked @{ */ - log::verbose("{} ccb to lcb, alloc {}, lcb {}, role {}, pid 0x{:x}", i, p_ccb->allocated, - fmt::ptr(p_ccb->p_lcb), p_ccb->cc.role, p_ccb->cc.pid); + log::verbose("{} ccb to lcb, alloc {}, role {}, pid 0x{:04x}", i, p_ccb->allocated, + avct_role_text(p_ccb->cc.role), p_ccb->cc.pid); if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { /* if bound to this lcb send connect confirm event */ - if (p_ccb->cc.role == AVCT_INT) { + if (p_ccb->cc.role == AVCT_ROLE_INITIATOR) { /** @} */ bind = true; if (!stack::l2cap::get_interface().L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH)) { - log::warn("Unable to set L2CAP transmit high priority peer:{} cid:{}", + log::warn("Unable to set L2CAP transmit high priority peer:{} lcid:0x{:04x}", p_ccb->p_lcb->peer_addr, p_lcb->ch_lcid); } p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, 0, @@ -269,7 +271,7 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { */ /** M: to avoid avctp collision, make sure the collision can be checked @{ */ - else if ((p_ccb->cc.role == AVCT_ACP) && avct_lcb_has_pid(p_lcb, p_ccb->cc.pid)) { + else if ((p_ccb->cc.role == AVCT_ROLE_ACCEPTOR) && avct_lcb_has_pid(p_lcb, p_ccb->cc.pid)) { /* bind ccb to lcb and send connect ind event */ if (is_originater) { log::error("int exist, unbind acp handle:{}", i); @@ -279,7 +281,7 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { p_ccb->p_lcb = p_lcb; if (!stack::l2cap::get_interface().L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH)) { - log::warn("Unable to set L2CAP transmit high priority peer:{} cid:{}", + log::warn("Unable to set L2CAP transmit high priority peer:{} lcid:0x{:04x}", p_ccb->p_lcb->peer_addr, p_lcb->ch_lcid); } p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, 0, @@ -297,7 +299,7 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { bind = true; if (!stack::l2cap::get_interface().L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH)) { - log::warn("Unable to set L2CAP transmit high priority peer:{} cid:{}", + log::warn("Unable to set L2CAP transmit high priority peer:{} lcid:0x{:04x}", p_ccb->p_lcb->peer_addr, p_lcb->ch_lcid); } p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, 0, @@ -305,14 +307,14 @@ void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { } /* if unbound acceptor and lcb doesn't already have a ccb for this PID */ - else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) && + else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ROLE_ACCEPTOR) && (avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL)) { /* bind ccb to lcb and send connect ind event */ bind = true; p_ccb->p_lcb = p_lcb; if (!stack::l2cap::get_interface().L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH)) { - log::warn("Unable to set L2CAP transmit high priority peer:{} cid:{}", + log::warn("Unable to set L2CAP transmit high priority peer:{} lcid:0x{:04x}", p_ccb->p_lcb->peer_addr, p_lcb->ch_lcid); } p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, 0, @@ -369,7 +371,7 @@ void avct_lcb_close_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* /* p_data */) { for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { - if (p_ccb->cc.role == AVCT_INT) { + if (p_ccb->cc.role == AVCT_ROLE_INITIATOR) { avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT, 0, &p_lcb->peer_addr); } else { p_ccb->p_lcb = NULL; @@ -406,7 +408,7 @@ void avct_lcb_close_cfm(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { event = AVCT_DISCONNECT_IND_EVT; } - if (p_ccb->cc.role == AVCT_INT) { + if (p_ccb->cc.role == AVCT_ROLE_INITIATOR) { avct_ccb_dealloc(p_ccb, event, p_data->result, &p_lcb->peer_addr); } else { p_ccb->p_lcb = NULL; @@ -714,7 +716,7 @@ void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { } /* PID not found; drop message */ - log::warn("No ccb for PID={:x}", pid); + log::warn("No ccb for PID=0x{:04x}", pid); osi_free_and_reset((void**)&p_data->p_buf); /* if command send reject */ @@ -727,7 +729,7 @@ void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) { UINT16_TO_BE_STREAM(p, pid); if (stack::l2cap::get_interface().L2CA_DataWrite(p_lcb->ch_lcid, p_buf) != tL2CAP_DW_RESULT::SUCCESS) { - log::warn("Unable to write L2CAP data peer:{} cid:{} len:{}", p_lcb->peer_addr, + log::warn("Unable to write L2CAP data peer:{} lcid:0x{:04x} len:{}", p_lcb->peer_addr, p_lcb->ch_lcid, p_buf->len); } } diff --git a/system/stack/avdt/avdt_api.cc b/system/stack/avdt/avdt_api.cc index d293517a54..6304e78255 100644 --- a/system/stack/avdt/avdt_api.cc +++ b/system/stack/avdt/avdt_api.cc @@ -35,6 +35,7 @@ #include "avdtc_api.h" #include "bta/include/bta_sec_api.h" #include "internal_include/bt_target.h" +#include "os/logging/log_adapter.h" #include "stack/include/a2dp_codec_api.h" #include "stack/include/bt_hdr.h" #include "stack/include/l2cap_interface.h" diff --git a/system/stack/avdt/avdt_msg.cc b/system/stack/avdt/avdt_msg.cc index d8d5269340..4241cd741a 100644 --- a/system/stack/avdt/avdt_msg.cc +++ b/system/stack/avdt/avdt_msg.cc @@ -35,7 +35,6 @@ #include "avdt_int.h" #include "avdtc_api.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/avrc/avrc_api.cc b/system/stack/avrc/avrc_api.cc index 60d1da067e..28f6f85064 100644 --- a/system/stack/avrc/avrc_api.cc +++ b/system/stack/avrc/avrc_api.cc @@ -31,7 +31,6 @@ #include "btif/include/btif_av.h" #include "btif/include/btif_config.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" #include "osi/include/properties.h" @@ -42,9 +41,6 @@ #include "storage/config_keys.h" #include "types/raw_address.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; /***************************************************************************** @@ -157,7 +153,7 @@ void avrc_flush_cmd_q(uint8_t handle) { * Returns Nothing. * *****************************************************************************/ -void avrc_process_timeout(void* data) { +static void avrc_process_timeout(void* data) { tAVRC_PARAM* param = (tAVRC_PARAM*)data; log::verbose("AVRC: command timeout (handle=0x{:02x}, label=0x{:02x})", param->handle, @@ -1063,16 +1059,15 @@ uint16_t AVRC_GetProfileVersion() { * *****************************************************************************/ uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb, const RawAddress& peer_addr) { - uint16_t status; - tAVCT_CC cc; - - cc.p_ctrl_cback = avrc_ctrl_cback; /* Control callback */ - cc.p_msg_cback = avrc_msg_cback; /* Message callback */ - cc.pid = UUID_SERVCLASS_AV_REMOTE_CONTROL; /* Profile ID */ - cc.role = p_ccb->conn; /* Initiator/acceptor role */ - cc.control = p_ccb->control; /* Control role (Control/Target) */ - - status = AVCT_CreateConn(p_handle, &cc, peer_addr); + tAVCT_CC cc = { + .p_ctrl_cback = avrc_ctrl_cback, /* Control callback */ + .p_msg_cback = avrc_msg_cback, /* Message callback */ + .pid = UUID_SERVCLASS_AV_REMOTE_CONTROL, /* Profile ID */ + .role = p_ccb->conn, /* Initiator/acceptor role */ + .control = p_ccb->control, /* Control role (Control/Target) */ + }; + + uint16_t status = AVCT_CreateConn(p_handle, &cc, peer_addr); if (status == AVCT_SUCCESS) { avrc_cb.ccb[*p_handle] = *p_ccb; memset(&avrc_cb.ccb_int[*p_handle], 0, sizeof(tAVRC_CONN_INT_CB)); @@ -1081,7 +1076,8 @@ uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb, const RawAddress& pe avrc_cb.ccb_int[*p_handle].tle = alarm_new("avrcp.commandTimer"); avrc_cb.ccb_int[*p_handle].cmd_q = fixed_queue_new(SIZE_MAX); } - log::verbose("role: {}, control:{} status:{}, handle:{}", cc.role, cc.control, status, *p_handle); + log::verbose("role: {}, control:0x{:x} status:{}, handle:{}", avct_role_text(cc.role), cc.control, + status, *p_handle); return status; } @@ -1124,7 +1120,7 @@ uint16_t AVRC_Close(uint8_t handle) { * the connection. * *****************************************************************************/ -uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role) { +uint16_t AVRC_OpenBrowse(uint8_t handle, tAVCT_ROLE conn_role) { return AVCT_CreateBrowse(handle, conn_role); } diff --git a/system/stack/avrc/avrc_bld_ct.cc b/system/stack/avrc/avrc_bld_ct.cc index 3ec2164046..a68c9dca9d 100644 --- a/system/stack/avrc/avrc_bld_ct.cc +++ b/system/stack/avrc/avrc_bld_ct.cc @@ -25,7 +25,6 @@ #include "avrc_defs.h" #include "avrc_int.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" diff --git a/system/stack/avrc/avrc_bld_tg.cc b/system/stack/avrc/avrc_bld_tg.cc index 6390232293..a057a03b53 100644 --- a/system/stack/avrc/avrc_bld_tg.cc +++ b/system/stack/avrc/avrc_bld_tg.cc @@ -24,16 +24,12 @@ #include "avrc_defs.h" #include "avrc_int.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/avct/avct_defs.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; /***************************************************************************** @@ -709,7 +705,7 @@ static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR* p_pkt * Otherwise, the error code. * ******************************************************************************/ -tAVRC_STS avrc_bld_group_navigation_rsp(uint16_t navi_id, BT_HDR* p_pkt) { +static tAVRC_STS avrc_bld_group_navigation_rsp(uint16_t navi_id, BT_HDR* p_pkt) { if (!AVRC_IS_VALID_GROUP(navi_id)) { log::error("bad navigation op id: {}", navi_id); return AVRC_STS_BAD_PARAM; diff --git a/system/stack/avrc/avrc_pars_ct.cc b/system/stack/avrc/avrc_pars_ct.cc index 045cee3dd2..b72fa63b43 100644 --- a/system/stack/avrc/avrc_pars_ct.cc +++ b/system/stack/avrc/avrc_pars_ct.cc @@ -21,14 +21,10 @@ #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "stack/include/bt_types.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; /***************************************************************************** @@ -133,7 +129,8 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg, tAVRC_RESPONSE* p return status; } -tAVRC_STS avrc_parse_notification_rsp(uint8_t* p_stream, uint16_t len, tAVRC_REG_NOTIF_RSP* p_rsp) { +static tAVRC_STS avrc_parse_notification_rsp(uint8_t* p_stream, uint16_t len, + tAVRC_REG_NOTIF_RSP* p_rsp) { uint32_t min_len = 1; if (len < min_len) { diff --git a/system/stack/avrc/avrc_pars_tg.cc b/system/stack/avrc/avrc_pars_tg.cc index b178fd5acb..dd4f9bdcfe 100644 --- a/system/stack/avrc/avrc_pars_tg.cc +++ b/system/stack/avrc/avrc_pars_tg.cc @@ -21,7 +21,6 @@ #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" -#include "os/log.h" #include "stack/include/bt_types.h" using namespace bluetooth; diff --git a/system/stack/avrc/avrc_sdp.cc b/system/stack/avrc/avrc_sdp.cc index cb209dde09..61ba721b5f 100644 --- a/system/stack/avrc/avrc_sdp.cc +++ b/system/stack/avrc/avrc_sdp.cc @@ -28,7 +28,7 @@ #include "avrc_api.h" #include "avrc_int.h" -#include "os/log.h" +#include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" #include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" @@ -65,16 +65,19 @@ static uint16_t a2dp_attr_list_sdp[] = { * Returns Nothing. * *****************************************************************************/ -static void avrc_sdp_cback(const RawAddress& /* bd_addr */, tSDP_STATUS status) { - log::verbose("status: {}", status); +static void avrc_sdp_cback(const RawAddress& bd_addr, tSDP_STATUS status) { + log::verbose("peer:{} status: {}", bd_addr, status); /* reset service_uuid, so can start another find service */ avrc_cb.service_uuid = 0; /* return info from sdp record in app callback function */ - avrc_cb.find_cback.Run(status); - - return; + if (!avrc_cb.find_cback.is_null()) { + avrc_cb.find_cback.Run(status); + } else { + log::warn("Received SDP callback with NULL callback peer:{} status:{}", bd_addr, + sdp_status_text(status)); + } } /****************************************************************************** @@ -247,7 +250,7 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, tSDP_PROTOCOL_ELEM avrc_proto_desc_list[AVRC_NUM_PROTO_ELEMS]; avrc_proto_desc_list[0].num_params = 1; avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; - avrc_proto_desc_list[0].params[0] = AVCT_PSM; + avrc_proto_desc_list[0].params[0] = BT_PSM_AVCTP; avrc_proto_desc_list[0].params[1] = 0; for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++) { avrc_proto_desc_list[index].num_params = 1; @@ -271,7 +274,7 @@ uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name, avrc_add_proto_desc_lists[i].num_elems = 2; avrc_add_proto_desc_lists[i].list_elem[0].num_params = 1; avrc_add_proto_desc_lists[i].list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP; - avrc_add_proto_desc_lists[i].list_elem[0].params[0] = AVCT_BR_PSM; + avrc_add_proto_desc_lists[i].list_elem[0].params[0] = BT_PSM_AVCTP_BROWSE; avrc_add_proto_desc_lists[i].list_elem[0].params[1] = 0; avrc_add_proto_desc_lists[i].list_elem[1].num_params = 1; avrc_add_proto_desc_lists[i].list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP; diff --git a/system/stack/avrc/avrc_utils.cc b/system/stack/avrc/avrc_utils.cc index cf2d428385..6e07b12d73 100644 --- a/system/stack/avrc/avrc_utils.cc +++ b/system/stack/avrc/avrc_utils.cc @@ -22,7 +22,6 @@ #include "avrc_api.h" #include "avrc_int.h" -#include "os/log.h" #include "stack/include/bt_types.h" using namespace bluetooth; diff --git a/system/stack/btm/btm_ble_addr.cc b/system/stack/btm/btm_ble_addr.cc index 308a69cd85..aae99cc80f 100644 --- a/system/stack/btm/btm_ble_addr.cc +++ b/system/stack/btm/btm_ble_addr.cc @@ -36,7 +36,6 @@ #include "crypto_toolbox/crypto_toolbox.h" #include "hci/controller_interface.h" #include "main/shim/entry.h" -#include "os/log.h" #include "stack/btm/btm_int_types.h" #include "stack/include/acl_api.h" #include "stack/include/bt_octets.h" diff --git a/system/stack/btm/btm_devctl.cc b/system/stack/btm/btm_devctl.cc index 86f4af00e4..d22fba73c7 100644 --- a/system/stack/btm/btm_devctl.cc +++ b/system/stack/btm/btm_devctl.cc @@ -38,7 +38,7 @@ #include "main/shim/entry.h" #include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sec.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/include/acl_api.h" #include "stack/include/acl_api_types.h" #include "stack/include/bt_types.h" diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h index ddebeb9439..5e563e9860 100644 --- a/system/stack/btm/btm_iso_impl.h +++ b/system/stack/btm/btm_iso_impl.h @@ -33,7 +33,6 @@ #include "internal_include/stack_config.h" #include "main/shim/entry.h" #include "main/shim/hci_layer.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_types.h" @@ -58,7 +57,8 @@ static constexpr uint8_t kStateFlagIsCancelled = 0x20; constexpr char kBtmLogTag[] = "ISO"; struct iso_sync_info { - uint16_t seq_nb; + uint16_t tx_seq_nb; + uint16_t rx_seq_nb; }; struct iso_base { @@ -160,7 +160,7 @@ struct iso_impl { auto cis = std::unique_ptr<iso_cis>(new iso_cis()); cis->cig_id = cig_id; cis->sdu_itv = sdu_itv_mtos; - cis->sync_info = {.seq_nb = 0}; + cis->sync_info = {.tx_seq_nb = 0, .rx_seq_nb = 0}; cis->used_credits = 0; cis->state_flags = kStateFlagsNone; conn_hdl_to_cis_map_[conn_handle] = std::move(cis); @@ -529,8 +529,8 @@ struct iso_impl { /* Calculate sequence number for the ISO data packet. * It should be incremented by 1 every SDU Interval. */ - uint16_t seq_nb = iso->sync_info.seq_nb; - iso->sync_info.seq_nb = (seq_nb + 1) & 0xffff; + uint16_t seq_nb = iso->sync_info.tx_seq_nb; + iso->sync_info.tx_seq_nb = (seq_nb + 1) & 0xffff; if (iso_credits_ == 0 || data_len > iso_buffer_size_) { iso->cr_stats.credits_underflow_bytes += data_len; @@ -682,7 +682,7 @@ struct iso_impl { auto bis = std::unique_ptr<iso_bis>(new iso_bis()); bis->big_handle = evt.big_id; bis->sdu_itv = last_big_create_req_sdu_itv_; - bis->sync_info = {.seq_nb = 0}; + bis->sync_info = {.tx_seq_nb = 0, .rx_seq_nb = 0}; bis->used_credits = 0; bis->state_flags = kStateFlagIsBroadcast; conn_hdl_to_bis_map_[conn_handle] = std::move(bis); @@ -807,8 +807,8 @@ struct iso_impl { STREAM_TO_UINT16(seq_nb, stream); - uint16_t expected_seq_nb = iso->sync_info.seq_nb; - iso->sync_info.seq_nb = (seq_nb + 1) & 0xffff; + uint16_t expected_seq_nb = iso->sync_info.rx_seq_nb; + iso->sync_info.rx_seq_nb = (seq_nb + 1) & 0xffff; evt.evt_lost = ((1 << 16) + seq_nb - expected_seq_nb) & 0xffff; if (evt.evt_lost > 0) { diff --git a/system/stack/btm/btm_sco_hci.cc b/system/stack/btm/btm_sco_hci.cc index 81fadb5cdc..d27d823cbd 100644 --- a/system/stack/btm/btm_sco_hci.cc +++ b/system/stack/btm/btm_sco_hci.cc @@ -28,7 +28,6 @@ #include "bta/ag/bta_ag_int.h" #include "btif/include/core_callbacks.h" #include "btif/include/stack_manager_t.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/btm/btm_sco.h" #include "udrv/include/uipc.h" diff --git a/system/stack/btm/btm_sco_hfp_hal_linux.cc b/system/stack/btm/btm_sco_hfp_hal_linux.cc index 018ba1fd65..9ca83962ee 100644 --- a/system/stack/btm/btm_sco_hfp_hal_linux.cc +++ b/system/stack/btm/btm_sco_hfp_hal_linux.cc @@ -23,7 +23,6 @@ #include "hci/controller_interface.h" #include "main/shim/entry.h" -#include "os/log.h" #include "osi/include/properties.h" #include "stack/btm/btm_sco_hfp_hal.h" #include "stack/include/hcimsgs.h" diff --git a/system/stack/btm/btm_sec_cb.cc b/system/stack/btm/btm_sec_cb.cc index 3e87d19810..60a2f0398e 100644 --- a/system/stack/btm/btm_sec_cb.cc +++ b/system/stack/btm/btm_sec_cb.cc @@ -25,7 +25,6 @@ #include "internal_include/bt_trace.h" #include "internal_include/stack_config.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" #include "osi/include/list.h" diff --git a/system/stack/btm/btm_security_client_interface.cc b/system/stack/btm/btm_security_client_interface.cc index a8a4a1c556..f2d397a9a7 100644 --- a/system/stack/btm/btm_security_client_interface.cc +++ b/system/stack/btm/btm_security_client_interface.cc @@ -19,7 +19,6 @@ #include <bluetooth/log.h> -#include "os/log.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" #include "stack/btm/btm_sec_cb.h" diff --git a/system/stack/btm/hfp_lc3_decoder.cc b/system/stack/btm/hfp_lc3_decoder.cc index 30e30d1ffc..245527b0dc 100644 --- a/system/stack/btm/hfp_lc3_decoder.cc +++ b/system/stack/btm/hfp_lc3_decoder.cc @@ -23,7 +23,6 @@ #include <cstring> -#include "os/log.h" #include "osi/include/allocator.h" using namespace bluetooth; diff --git a/system/stack/btm/hfp_lc3_decoder_linux.cc b/system/stack/btm/hfp_lc3_decoder_linux.cc index b30da4ff19..0ba81c9dd0 100644 --- a/system/stack/btm/hfp_lc3_decoder_linux.cc +++ b/system/stack/btm/hfp_lc3_decoder_linux.cc @@ -23,7 +23,6 @@ #include "hfp_lc3_decoder.h" #include "mmc/codec_client/codec_client.h" #include "mmc/proto/mmc_config.pb.h" -#include "os/log.h" using namespace bluetooth; diff --git a/system/stack/btm/hfp_lc3_encoder.cc b/system/stack/btm/hfp_lc3_encoder.cc index 6e0cdb28df..9d909fef0d 100644 --- a/system/stack/btm/hfp_lc3_encoder.cc +++ b/system/stack/btm/hfp_lc3_encoder.cc @@ -23,7 +23,6 @@ #include <cstring> -#include "os/log.h" #include "osi/include/allocator.h" using namespace bluetooth; diff --git a/system/stack/btm/hfp_lc3_encoder_linux.cc b/system/stack/btm/hfp_lc3_encoder_linux.cc index 448e6403c2..21f8d55d68 100644 --- a/system/stack/btm/hfp_lc3_encoder_linux.cc +++ b/system/stack/btm/hfp_lc3_encoder_linux.cc @@ -21,7 +21,6 @@ #include "hfp_lc3_encoder.h" #include "mmc/codec_client/codec_client.h" #include "mmc/proto/mmc_config.pb.h" -#include "os/log.h" using namespace bluetooth; diff --git a/system/stack/btm/hfp_msbc_decoder.cc b/system/stack/btm/hfp_msbc_decoder.cc index 334cf91f9f..d1396a771d 100644 --- a/system/stack/btm/hfp_msbc_decoder.cc +++ b/system/stack/btm/hfp_msbc_decoder.cc @@ -24,7 +24,6 @@ #include "embdrv/sbc/decoder/include/oi_codec_sbc.h" #include "embdrv/sbc/decoder/include/oi_status.h" -#include "os/log.h" #define HFP_MSBC_PKT_LEN 60 #define HFP_MSBC_PCM_BYTES 240 diff --git a/system/stack/btm/security_device_record.h b/system/stack/btm/security_device_record.h index 14463ac211..c1037a40f4 100644 --- a/system/stack/btm/security_device_record.h +++ b/system/stack/btm/security_device_record.h @@ -26,7 +26,7 @@ #include "internal_include/bt_target.h" #include "macros.h" -#include "os/log.h" +#include "os/logging/log_adapter.h" #include "stack/include/bt_device_type.h" #include "stack/include/bt_name.h" #include "stack/include/bt_octets.h" diff --git a/system/stack/btu/main_thread.cc b/system/stack/btu/main_thread.cc index 03afc210f5..6223e66716 100644 --- a/system/stack/btu/main_thread.cc +++ b/system/stack/btu/main_thread.cc @@ -27,7 +27,6 @@ #include "common/message_loop_thread.h" #include "include/hardware/bluetooth.h" -#include "os/log.h" using bluetooth::common::MessageLoopThread; using namespace bluetooth; diff --git a/system/stack/gatt/connection_manager.cc b/system/stack/connection_manager/connection_manager.cc index 96278a9106..c29ac5d403 100644 --- a/system/stack/gatt/connection_manager.cc +++ b/system/stack/connection_manager/connection_manager.cc @@ -581,7 +581,10 @@ void dump(int fd) { dprintf(fd, "\tdevices attempting connection: %d", (int)bgconn_dev.size()); for (const auto& entry : bgconn_dev) { // TODO: confirm whether we need to replace this - dprintf(fd, "\n\t * %s: ", ADDRESS_TO_LOGGABLE_CSTR(entry.first)); + dprintf(fd, "\n\t * %s:\t\tin_accept_list: %s\t cap_targeted_announcements: %s", + ADDRESS_TO_LOGGABLE_CSTR(entry.first), + entry.second.is_in_accept_list ? "true" : "false", + entry.second.doing_targeted_announcements_conn.empty() ? "false" : "true"); if (!entry.second.doing_direct_conn.empty()) { dprintf(fd, "\n\t\tapps doing direct connect: "); @@ -596,14 +599,6 @@ void dump(int fd) { dprintf(fd, "%d, ", id); } } - if (!entry.second.doing_targeted_announcements_conn.empty()) { - dprintf(fd, "\n\t\tapps doing cap announcement connect: "); - for (const auto& id : entry.second.doing_targeted_announcements_conn) { - dprintf(fd, "%d, ", id); - } - } - dprintf(fd, "\n\t\t is in the allow list: %s", - entry.second.is_in_accept_list ? "true" : "false"); } dprintf(fd, "\n"); } diff --git a/system/stack/gatt/connection_manager.h b/system/stack/connection_manager/connection_manager.h index a9a5256261..a9a5256261 100644 --- a/system/stack/gatt/connection_manager.h +++ b/system/stack/connection_manager/connection_manager.h diff --git a/system/stack/fuzzers/avrc_fuzzer.cc b/system/stack/fuzzers/avrc_fuzzer.cc index 1592b707fd..be0c80f32c 100644 --- a/system/stack/fuzzers/avrc_fuzzer.cc +++ b/system/stack/fuzzers/avrc_fuzzer.cc @@ -20,18 +20,17 @@ #include <cstdint> #include <functional> -#include <optional> #include <vector> #include "osi/include/allocator.h" #include "stack/include/avct_api.h" #include "stack/include/avrc_api.h" +#include "stack/include/bt_psm_types.h" #include "test/fake/fake_osi.h" #include "test/mock/mock_btif_config.h" #include "test/mock/mock_stack_acl.h" #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 "types/bluetooth/uuid.h" // TODO(b/369381361) Enfore -Wmissing-prototypes @@ -81,11 +80,11 @@ public: [](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) { - log::assert_that(psm == AVCT_PSM || psm == AVCT_BR_PSM, - "assert failed: psm == AVCT_PSM || psm == AVCT_BR_PSM"); - if (psm == AVCT_PSM) { + log::assert_that(psm == BT_PSM_AVCTP || psm == BT_PSM_AVCTP_BROWSE, + "assert failed: psm == BT_PSM_AVCTP || psm == BT_PSM_AVCTP_BROWSE"); + if (psm == BT_PSM_AVDTP) { avct_appl = p_cb_info; - } else if (psm == AVCT_BR_PSM) { + } else if (psm == BT_PSM_AVCTP_BROWSE) { avct_br_appl = p_cb_info; } return psm; @@ -186,7 +185,7 @@ static void Fuzz(const uint8_t* data, size_t size) { tAVRC_CONN_CB ccb = { .ctrl_cback = base::Bind(ctrl_cb), .msg_cback = base::Bind(msg_cb), - .conn = (uint8_t)(is_initiator ? AVCT_INT : AVCT_ACP), + .conn = (is_initiator ? AVCT_ROLE_INITIATOR : AVCT_ROLE_ACCEPTOR), .control = (uint8_t)(is_controller ? AVCT_CONTROL : AVCT_TARGET), }; diff --git a/system/stack/fuzzers/l2cap_fuzzer.cc b/system/stack/fuzzers/l2cap_fuzzer.cc index fd68f98486..2c5c3d2cde 100644 --- a/system/stack/fuzzers/l2cap_fuzzer.cc +++ b/system/stack/fuzzers/l2cap_fuzzer.cc @@ -36,6 +36,7 @@ #include "stack/include/l2cap_interface.h" #include "stack/include/l2cap_module.h" #include "stack/include/l2cdefs.h" +#include "stack/l2cap/l2c_int.h" #include "test/fake/fake_osi.h" #include "test/mock/mock_main_shim_entry.h" #include "test/mock/mock_stack_acl.h" @@ -161,8 +162,6 @@ constexpr uint16_t kSmpBrHndl = 0x0222; constexpr uint16_t kNumClassicAclBuffer = 100; constexpr uint16_t kNumLeAclBuffer = 100; -void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, const RawAddress& p_bda); - static void Fuzz(const uint8_t* data, size_t size) { memset(&btm_cb, 0, sizeof(btm_cb)); diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc index d9d7f051d9..7ed0fe0516 100644 --- a/system/stack/gatt/gatt_api.cc +++ b/system/stack/gatt/gatt_api.cc @@ -37,7 +37,7 @@ #include "osi/include/allocator.h" #include "stack/arbiter/acl_arbiter.h" #include "stack/btm/btm_dev.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/gatt/gatt_int.h" #include "stack/include/ais_api.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h index 485c7f6a34..59dc338b5d 100644 --- a/system/stack/gatt/gatt_int.h +++ b/system/stack/gatt/gatt_int.h @@ -34,6 +34,7 @@ #include "gatt_api.h" #include "internal_include/bt_target.h" #include "macros.h" +#include "os/logging/log_adapter.h" #include "osi/include/fixed_queue.h" #include "stack/include/bt_hdr.h" #include "types/bluetooth/uuid.h" diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc index bc559a5715..f5591d2194 100644 --- a/system/stack/gatt/gatt_main.cc +++ b/system/stack/gatt/gatt_main.cc @@ -28,7 +28,6 @@ #include "btif/include/btif_dm.h" #include "btif/include/btif_storage.h" #include "btif/include/stack_manager_t.h" -#include "connection_manager.h" #include "device/include/interop.h" #include "internal_include/bt_target.h" #include "internal_include/stack_config.h" @@ -38,6 +37,7 @@ #include "stack/arbiter/acl_arbiter.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/eatt/eatt.h" #include "stack/gatt/gatt_int.h" #include "stack/include/acl_api.h" diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc index 72083acb50..d159bbd794 100644 --- a/system/stack/gatt/gatt_utils.cc +++ b/system/stack/gatt/gatt_utils.cc @@ -38,8 +38,8 @@ #include "osi/include/properties.h" #include "stack/btm/btm_dev.h" #include "stack/btm/btm_sec.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/eatt/eatt.h" -#include "stack/gatt/connection_manager.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_psm_types.h" diff --git a/system/stack/hid/hidd_api.cc b/system/stack/hid/hidd_api.cc index 3a213d4c1d..79f4d1d7b0 100644 --- a/system/stack/hid/hidd_api.cc +++ b/system/stack/hid/hidd_api.cc @@ -34,7 +34,6 @@ #include "hidd_int.h" #include "hiddefs.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" diff --git a/system/stack/hid/hidh_api.cc b/system/stack/hid/hidh_api.cc index 72c30e3f13..f415c48fb1 100644 --- a/system/stack/hid/hidh_api.cc +++ b/system/stack/hid/hidh_api.cc @@ -34,7 +34,6 @@ #include "hiddefs.h" #include "hidh_int.h" #include "internal_include/bt_target.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_uuid16.h" diff --git a/system/stack/include/avct_api.h b/system/stack/include/avct_api.h index 0ac2399b93..3693cdcd0f 100644 --- a/system/stack/include/avct_api.h +++ b/system/stack/include/avct_api.h @@ -26,8 +26,9 @@ #define AVCT_API_H #include <cstdint> +#include <string> -#include "internal_include/bt_target.h" +#include "include/macros.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" @@ -42,10 +43,6 @@ #define AVCT_PID_IN_USE 3 /* PID already in use */ #define AVCT_NOT_OPEN 4 /* Connection not open */ -/* PSM for AVCT. */ -#define AVCT_PSM 0x0017 -#define AVCT_BR_PSM 0x001B - /* Protocol revision numbers */ #define AVCT_REV_1_0 0x0100 #define AVCT_REV_1_2 0x0102 @@ -69,8 +66,18 @@ #define AVCT_BROWSE_OFFSET 17 /* the default offset for browsing channel */ /* Connection role. */ -#define AVCT_INT 0 /* Initiator connection */ -#define AVCT_ACP 1 /* Acceptor connection */ +typedef enum { + AVCT_ROLE_INITIATOR = 0, /* Initiator connection */ + AVCT_ROLE_ACCEPTOR = 1, /* Acceptor connection */ +} tAVCT_ROLE; + +inline std::string avct_role_text(const tAVCT_ROLE& role) { + switch (role) { + CASE_RETURN_TEXT(AVCT_ROLE_INITIATOR); + CASE_RETURN_TEXT(AVCT_ROLE_ACCEPTOR); + } + RETURN_UNKNOWN_TYPE_STRING(tAVCT_ROLE, role); +} /* Control role. */ #define AVCT_TARGET 1 /* target */ @@ -116,7 +123,7 @@ typedef struct { tAVCT_CTRL_CBACK* p_ctrl_cback; /* Control callback */ tAVCT_MSG_CBACK* p_msg_cback; /* Message callback */ uint16_t pid; /* Profile ID */ - uint8_t role; /* Initiator/acceptor role */ + tAVCT_ROLE role; /* Initiator/acceptor role */ uint8_t control; /* Control role (Control/Target) */ } tAVCT_CC; @@ -207,7 +214,7 @@ uint16_t AVCT_RemoveConn(uint8_t handle); * Returns AVCT_SUCCESS if successful, otherwise error. * ******************************************************************************/ -uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role); +uint16_t AVCT_CreateBrowse(uint8_t handle, tAVCT_ROLE role); /******************************************************************************* * @@ -273,4 +280,18 @@ uint16_t AVCT_GetPeerMtu(uint8_t handle); ******************************************************************************/ uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg); +/******************************************************************************* +** +** Function AVCT_Dumpsys +** +** Description This function provides dumpsys data during the dumpsys +** procedure. +** +** Parameters: fd: Descriptor used to write the AVCT internals +** +** Returns void +** +*******************************************************************************/ +void AVCT_Dumpsys(int fd); + #endif /* AVCT_API_H */ diff --git a/system/stack/include/avdt_api.h b/system/stack/include/avdt_api.h index 30a7ebea26..c1275db105 100644 --- a/system/stack/include/avdt_api.h +++ b/system/stack/include/avdt_api.h @@ -33,7 +33,6 @@ #include "internal_include/bt_target.h" #include "macros.h" -#include "os/log.h" #include "stack/include/bt_hdr.h" #include "types/raw_address.h" diff --git a/system/stack/include/avrc_api.h b/system/stack/include/avrc_api.h index 918bdfb436..589ddb5021 100644 --- a/system/stack/include/avrc_api.h +++ b/system/stack/include/avrc_api.h @@ -65,12 +65,6 @@ /* If conflict, allow the other side to succeed */ #define AVRC_CT_PASSIVE 4 -/* Connection role */ -/* initiator */ -#define AVRC_CONN_INT AVCT_INT -/* Acceptor */ -#define AVRC_CONN_ACP AVCT_ACP - /* AVRC CTRL events */ /* AVRC_OPEN_IND_EVT event is sent when the connection is successfully opened. * This eventis sent in response to an AVRC_Open(). */ @@ -201,7 +195,7 @@ typedef struct { * attribute filter * to be ATTR_ID_SERVICE_CLASS_ID_LIST, * ATTR_ID_BT_PROFILE_DESC_LIST, - * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and + * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME, * ATTR_ID_PROVIDER_NAME. * If not NULL, the input is taken as the filter. */ } tAVRC_SDP_DB_PARAMS; @@ -229,7 +223,7 @@ typedef struct { tAVRC_CTRL_CBACK ctrl_cback; /* application control callback */ tAVRC_MSG_CBACK msg_cback; /* application message callback */ uint32_t company_id; /* the company ID */ - uint8_t conn; /* Connection role (Initiator/acceptor) */ + tAVCT_ROLE conn; /* Connection role (Initiator/acceptor) */ uint8_t control; /* Control role (Control/Target) */ } tAVRC_CONN_CB; @@ -460,7 +454,7 @@ uint16_t AVRC_Close(uint8_t handle); * the connection. * *****************************************************************************/ -uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role); +uint16_t AVRC_OpenBrowse(uint8_t handle, tAVCT_ROLE conn_role); /****************************************************************************** * diff --git a/system/stack/include/bt_psm_types.h b/system/stack/include/bt_psm_types.h index a5bb3e47e4..3f0716110b 100644 --- a/system/stack/include/bt_psm_types.h +++ b/system/stack/include/bt_psm_types.h @@ -36,9 +36,9 @@ enum tBT_PSM : uint16_t { BT_PSM_UPNP = 0x0015, BT_PSM_AVCTP = 0x0017, BT_PSM_AVDTP = 0x0019, - BT_PSM_AVCTP_13 = 0x001B, /* Advanced Control - Browsing */ - BT_PSM_UDI_CP = 0x001D, /* Unrestricted Digital Information Profile C-Plane */ - BT_PSM_ATT = 0x001F, /* Attribute Protocol */ + BT_PSM_AVCTP_BROWSE = 0x001B, /* Advanced Control - Browsing */ + BT_PSM_UDI_CP = 0x001D, /* Unrestricted Digital Information Profile C-Plane */ + BT_PSM_ATT = 0x001F, /* Attribute Protocol */ BT_PSM_EATT = 0x0027, /* We will not allocate a PSM in the reserved range to 3rd party apps */ @@ -58,7 +58,7 @@ inline std::string bt_psm_text(const tBT_PSM& psm) { CASE_RETURN_STRING_HEX04(BT_PSM_UPNP); CASE_RETURN_STRING_HEX04(BT_PSM_AVCTP); CASE_RETURN_STRING_HEX04(BT_PSM_AVDTP); - CASE_RETURN_STRING_HEX04(BT_PSM_AVCTP_13); + CASE_RETURN_STRING_HEX04(BT_PSM_AVCTP_BROWSE); CASE_RETURN_STRING_HEX04(BT_PSM_UDI_CP); CASE_RETURN_STRING_HEX04(BT_PSM_ATT); CASE_RETURN_STRING_HEX04(BT_PSM_EATT); diff --git a/system/stack/include/l2cap_acl_interface.h b/system/stack/include/l2cap_acl_interface.h index 811b5c1288..7751d14255 100644 --- a/system/stack/include/l2cap_acl_interface.h +++ b/system/stack/include/l2cap_acl_interface.h @@ -32,9 +32,6 @@ void acl_write_automatic_flush_timeout(const RawAddress& bd_addr, uint16_t flush // ACL data received from HCI-ACL void l2c_rcv_acl_data(BT_HDR* p_msg); -// Segments is sent to HCI-ACL -void l2c_link_segments_xmitted(BT_HDR* p_msg); - void l2cu_resubmit_pending_sec_req(const RawAddress* p_bda); void l2c_packets_completed(uint16_t handle, uint16_t num_sent); diff --git a/system/stack/include/l2cap_hci_link_interface.h b/system/stack/include/l2cap_hci_link_interface.h index 978aadade5..8699d1aa03 100644 --- a/system/stack/include/l2cap_hci_link_interface.h +++ b/system/stack/include/l2cap_hci_link_interface.h @@ -47,9 +47,6 @@ void l2cble_notify_le_connection(const RawAddress& bda); void l2cble_use_preferred_conn_params(const RawAddress& bda); -void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min, uint16_t int_max, - uint16_t latency, uint16_t timeout); - // Invoked when HCI mode is changed to HCI_MODE_ACTIVE or HCI_MODE_SNIFF void l2c_OnHciModeChangeSendPendingPackets(RawAddress remote); diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc index cb66ec209d..a233046a74 100644 --- a/system/stack/l2cap/l2c_api.cc +++ b/system/stack/l2cap/l2c_api.cc @@ -45,13 +45,11 @@ #include "stack/include/bt_hdr.h" #include "stack/include/bt_psm_types.h" #include "stack/include/btm_client_interface.h" +#include "stack/include/l2cap_module.h" #include "stack/include/main_thread.h" #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; extern fixed_queue_t* btu_general_alarm_queue; @@ -59,13 +57,6 @@ tL2C_AVDT_CHANNEL_INFO av_media_channels[MAX_ACTIVE_AVDT_CONN]; constexpr uint16_t L2CAP_LE_CREDIT_THRESHOLD = 64; -tBT_TRANSPORT l2c_get_transport_from_fixed_cid(uint16_t fixed_cid) { - if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID) { - return BT_TRANSPORT_LE; - } - return BT_TRANSPORT_BR_EDR; -} - uint16_t L2CA_RegisterWithSecurity(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, diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc index a00e0d17f4..9d69e5ab36 100644 --- a/system/stack/l2cap/l2c_ble.cc +++ b/system/stack/l2cap/l2c_ble.cc @@ -44,7 +44,7 @@ #include "stack/btm/btm_int_types.h" #include "stack/btm/btm_sec.h" #include "stack/btm/btm_sec_int_types.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/include/acl_api.h" #include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" @@ -53,21 +53,18 @@ #include "stack/include/btm_log_history.h" #include "stack/include/btm_status.h" #include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cap_controller_interface.h" +#include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cap_interface.h" #include "stack/include/l2cdefs.h" #include "stack/include/main_thread.h" #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; namespace { - constexpr char kBtmLogTag[] = "L2CAP"; - } extern tBTM_CB btm_cb; @@ -1280,8 +1277,8 @@ void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) { * Returns void * ******************************************************************************/ -void l2cble_sec_comp(RawAddress bda, tBT_TRANSPORT transport, void* /* p_ref_data */, - tBTM_STATUS btm_status) { +static void l2cble_sec_comp(RawAddress bda, tBT_TRANSPORT transport, void* /* p_ref_data */, + tBTM_STATUS btm_status) { tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE); tL2CAP_SEC_DATA* p_buf = NULL; uint8_t sec_act; diff --git a/system/stack/l2cap/l2c_ble_conn_params.cc b/system/stack/l2cap/l2c_ble_conn_params.cc index f617e59d5d..1e9d4ba7ab 100644 --- a/system/stack/l2cap/l2c_ble_conn_params.cc +++ b/system/stack/l2cap/l2c_ble_conn_params.cc @@ -38,14 +38,12 @@ #include "stack/include/acl_api.h" #include "stack/include/btm_ble_api_types.h" #include "stack/include/btm_client_interface.h" +#include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cap_interface.h" #include "stack/include/main_thread.h" #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; void l2cble_start_conn_update(tL2C_LCB* p_lcb); diff --git a/system/stack/l2cap/l2c_csm.cc b/system/stack/l2cap/l2c_csm.cc index 1c7021ffc7..776596a6f5 100644 --- a/system/stack/l2cap/l2c_csm.cc +++ b/system/stack/l2cap/l2c_csm.cc @@ -66,6 +66,75 @@ static void l2c_csm_send_connect_rsp(tL2C_CCB* p_ccb) { l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL); } +#if (L2CAP_CONFORMANCE_TESTING == TRUE) +#include "osi/include/properties.h" + +/* FCS Flag configuration for L2CAP/FOC/BV-04 and L2CAP/FOC/BV-05 + * Upper tester implementation for above two testcases where + * different FCS options need to be used in different steps. + */ + +/* L2CAP.TSp38, table 4.13 */ +static uint8_t pts_fcs_option_bv_04_c[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + +/* L2CAP.TSp38, table 4.68 */ +static uint8_t pts_fcs_option_bv_05_c[] = {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + +static uint8_t pts_foc_bv_test_id_property; + +static uint8_t pts_get_fcs_option(void) { + static size_t fcs_opt_iter = 0; + uint8_t* fcs_test_options = nullptr; + uint8_t iter_cnt = 0; + + uint8_t test_id = osi_property_get_int32("bluetooth.pts.l2cap.foc.bv.test", 0); + if (pts_foc_bv_test_id_property != test_id) { + pts_foc_bv_test_id_property = test_id; + fcs_opt_iter = 0; + } + + switch (test_id) { + case 4: + log::info("Proceed test L2CAP/FOC/BV-04-C"); + fcs_test_options = &pts_fcs_option_bv_04_c[0]; + iter_cnt = sizeof(pts_fcs_option_bv_04_c); + break; + case 5: + log::info("Proceed test L2CAP/FOC/BV-05-C"); + fcs_test_options = &pts_fcs_option_bv_05_c[0]; + iter_cnt = sizeof(pts_fcs_option_bv_05_c); + break; + default: + log::info("Proceed unknown test"); + return 1; + } + + log::info("fcs_opt_iter: {}, fcs option: {}", fcs_opt_iter, + fcs_opt_iter < iter_cnt ? fcs_test_options[fcs_opt_iter] : -1); + + if (fcs_opt_iter < iter_cnt) { + return fcs_test_options[fcs_opt_iter++]; + } + + log::info("Too many iterations: {}, return fcs = 0x01", fcs_opt_iter); + return 1; +} + +static void l2c_csm_send_config_req(tL2C_CCB* p_ccb); +static void l2c_ccb_pts_delay_config_timeout(void* data) { + tL2C_CCB* p_ccb = (tL2C_CCB*)data; + l2c_csm_send_config_req(p_ccb); +} +#endif + +static uint8_t get_fcs_option(void) { +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + return pts_get_fcs_option(); +#else + return 0x01; +#endif +} + // Send a config request and adjust the state machine static void l2c_csm_send_config_req(tL2C_CCB* p_ccb) { tL2CAP_CFG_INFO config{}; @@ -80,7 +149,7 @@ static void l2c_csm_send_config_req(tL2C_CCB* p_ccb) { /* Later l2cu_process_our_cfg_req() will check if remote supports it, and if not, it will be * cleared as per spec. */ config.fcs_present = true; - config.fcs = 1; + config.fcs = get_fcs_option(); } } p_ccb->our_cfg = config; @@ -506,7 +575,13 @@ static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event, void* p_dat if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE) { log::debug("Not LE connection, sending configure request"); l2c_csm_send_connect_rsp(p_ccb); +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + // TODO: when b/374014194 is solved on PTS side, revert change adding this delay. + alarm_set_on_mloop(p_ccb->pts_config_delay_timer, 5000, l2c_ccb_pts_delay_config_timeout, + p_ccb); +#else l2c_csm_send_config_req(p_ccb); +#endif } else { if (p_ccb->ecoc) { /* Handle Credit Based Connection */ diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h index 94396b7577..02a1fa66ad 100644 --- a/system/stack/l2cap/l2c_int.h +++ b/system/stack/l2cap/l2c_int.h @@ -282,6 +282,11 @@ struct tL2C_CCB { alarm_t* l2c_ccb_timer; /* CCB Timer Entry */ +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + alarm_t* pts_config_delay_timer; /* Used to delay sending CONFIGURATION_REQ to overcome PTS issue + */ +#endif + tL2C_RCB* p_rcb; /* Registration CB for this Channel */ #define IB_CFG_DONE 0x01 @@ -779,11 +784,12 @@ void l2cu_adjust_out_mps(tL2C_CCB* p_ccb); /* Functions provided by l2c_link.cc *********************************** */ + void l2c_link_timeout(tL2C_LCB* p_lcb); void l2c_info_resp_timer_timeout(void* data); void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, uint16_t local_cid, BT_HDR* p_buf); void l2c_link_adjust_allocation(void); - +void l2c_link_hci_conn_comp(tHCI_STATUS status, uint16_t handle, const RawAddress& p_bda); void l2c_link_sec_comp(RawAddress p_bda, tBT_TRANSPORT transport, void* p_ref_data, tBTM_STATUS status); void l2c_link_adjust_chnl_allocation(void); @@ -827,10 +833,11 @@ void l2c_fcr_stop_timer(tL2C_CCB* p_ccb); /* Functions provided by l2c_ble.cc *********************************** */ + bool l2cble_create_conn(tL2C_LCB* p_lcb); void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len); void l2c_ble_link_adjust_allocation(void); - +void l2cble_start_conn_update(tL2C_LCB* p_lcb); void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb); void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, tL2CAP_LE_RESULT_CODE result); void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb); diff --git a/system/stack/l2cap/l2c_link.cc b/system/stack/l2cap/l2c_link.cc index b7521ab677..3a3bb4290d 100644 --- a/system/stack/l2cap/l2c_link.cc +++ b/system/stack/l2cap/l2c_link.cc @@ -40,15 +40,13 @@ #include "stack/include/btm_status.h" #include "stack/include/hci_error_code.h" #include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cap_controller_interface.h" #include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cap_security_interface.h" #include "stack/l2cap/l2c_int.h" #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; extern tBTM_CB btm_cb; @@ -1151,45 +1149,6 @@ void l2c_packets_completed(uint16_t handle, uint16_t num_sent) { } } -/******************************************************************************* - * - * Function l2c_link_segments_xmitted - * - * Description This function is called from the HCI Interface when an ACL - * data packet segment is transmitted. - * - * Returns void - * - ******************************************************************************/ -void l2c_link_segments_xmitted(BT_HDR* p_msg) { - uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset; - - /* Extract the handle */ - uint16_t handle{HCI_INVALID_HANDLE}; - STREAM_TO_UINT16(handle, p); - handle = HCID_GET_HANDLE(handle); - - /* Find the LCB based on the handle */ - tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle); - if (p_lcb == nullptr) { - log::warn("Received segment complete for unknown connection handle:{}", handle); - osi_free(p_msg); - return; - } - - if (p_lcb->link_state != LST_CONNECTED) { - log::info("Received segment complete for unconnected connection handle:{}:", handle); - osi_free(p_msg); - return; - } - - /* Enqueue the buffer to the head of the transmit queue, and see */ - /* if we can transmit anything more. */ - list_prepend(p_lcb->link_xmit_data_q, p_msg); - - l2c_link_check_send_pkts(p_lcb, 0, NULL); -} - tBTM_STATUS l2cu_ConnectAclForSecurity(const RawAddress& bd_addr) { tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR); if (p_lcb && (p_lcb->link_state == LST_CONNECTED || p_lcb->link_state == LST_CONNECTING)) { @@ -1222,7 +1181,7 @@ void l2cble_update_sec_act(const RawAddress& bd_addr, uint16_t sec_act) { * Returns pointer to CCB or NULL * ******************************************************************************/ -tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* p_lcb) { +static tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* p_lcb) { tL2C_CCB* p_serve_ccb = NULL; tL2C_CCB* p_ccb; @@ -1320,7 +1279,7 @@ tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* p_lcb) { * Returns pointer to buffer or NULL * ******************************************************************************/ -BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb, tL2C_TX_COMPLETE_CB_INFO* p_cbi) { +static BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb, tL2C_TX_COMPLETE_CB_INFO* p_cbi) { tL2C_CCB* p_ccb; BT_HDR* p_buf; diff --git a/system/stack/l2cap/l2c_main.cc b/system/stack/l2cap/l2c_main.cc index 9259283109..057b474f5b 100644 --- a/system/stack/l2cap/l2c_main.cc +++ b/system/stack/l2cap/l2c_main.cc @@ -35,14 +35,13 @@ #include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" #include "stack/include/hcimsgs.h" // HCID_GET_ +#include "stack/include/l2cap_acl_interface.h" #include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cap_interface.h" +#include "stack/include/l2cap_module.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; /******************************************************************************/ diff --git a/system/stack/l2cap/l2c_utils.cc b/system/stack/l2cap/l2c_utils.cc index 6497bb1c37..0e923a559c 100644 --- a/system/stack/l2cap/l2c_utils.cc +++ b/system/stack/l2cap/l2c_utils.cc @@ -44,19 +44,16 @@ #include "stack/include/hci_error_code.h" #include "stack/include/hcidefs.h" #include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cap_controller_interface.h" #include "stack/include/l2cap_hci_link_interface.h" #include "stack/include/l2cap_interface.h" +#include "stack/include/l2cap_security_interface.h" #include "stack/include/l2cdefs.h" #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - using namespace bluetooth; -tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* p_lcb); // TODO Move - /* The offset in a buffer that L2CAP will use when building commands. */ #define L2CAP_SEND_CMD_OFFSET 0 @@ -305,7 +302,7 @@ bool l2c_is_cmd_rejected(uint8_t cmd_code, uint8_t signal_id, tL2C_LCB* p_lcb) { * Returns Pointer to allocated packet or NULL if no resources * ******************************************************************************/ -BT_HDR* l2cu_build_header(tL2C_LCB* p_lcb, uint16_t len, uint8_t cmd, uint8_t signal_id) { +static BT_HDR* l2cu_build_header(tL2C_LCB* p_lcb, uint16_t len, uint8_t cmd, uint8_t signal_id) { BT_HDR* p_buf = (BT_HDR*)osi_malloc(L2CAP_CMD_BUF_SIZE); uint8_t* p; @@ -348,7 +345,7 @@ BT_HDR* l2cu_build_header(tL2C_LCB* p_lcb, uint16_t len, uint8_t cmd, uint8_t si * Returns void * ******************************************************************************/ -void l2cu_adj_id(tL2C_LCB* p_lcb) { +static void l2cu_adj_id(tL2C_LCB* p_lcb) { if (p_lcb->signal_id == 0) { p_lcb->signal_id++; } @@ -1466,6 +1463,11 @@ tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid, bool is_eatt) { alarm_free(p_ccb->l2c_ccb_timer); p_ccb->l2c_ccb_timer = alarm_new("l2c.l2c_ccb_timer"); +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + alarm_free(p_ccb->pts_config_delay_timer); + p_ccb->pts_config_delay_timer = alarm_new("pts.delay"); +#endif + l2c_link_adjust_chnl_allocation(); if (p_lcb != NULL) { @@ -1575,6 +1577,11 @@ void l2cu_release_ccb(tL2C_CCB* p_ccb) { alarm_free(p_ccb->l2c_ccb_timer); p_ccb->l2c_ccb_timer = NULL; +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + alarm_free(p_ccb->pts_config_delay_timer); + p_ccb->pts_config_delay_timer = NULL; +#endif + fixed_queue_free(p_ccb->xmit_hold_q, osi_free); p_ccb->xmit_hold_q = NULL; @@ -2199,28 +2206,6 @@ void l2cu_create_conn_br_edr(tL2C_LCB* p_lcb) { /******************************************************************************* * - * Function l2cu_get_num_hi_priority - * - * Description Gets the number of high priority channels. - * - * Returns - * - ******************************************************************************/ -uint8_t l2cu_get_num_hi_priority(void) { - uint8_t no_hi = 0; - int xx; - tL2C_LCB* p_lcb = &l2cb.lcb_pool[0]; - - for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) { - if ((p_lcb->in_use) && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) { - no_hi++; - } - } - return no_hi; -} - -/******************************************************************************* - * * Function l2cu_create_conn_after_switch * * Description This continues a connection creation possibly after diff --git a/system/stack/pan/pan_api.cc b/system/stack/pan/pan_api.cc index 496a92050a..1fb209a17b 100644 --- a/system/stack/pan/pan_api.cc +++ b/system/stack/pan/pan_api.cc @@ -36,7 +36,7 @@ #include "bta/sys/bta_sys.h" #include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" -#include "os/log.h" +#include "os/logging/log_adapter.h" #include "osi/include/allocator.h" #include "stack/include/bnep_api.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/pan/pan_main.cc b/system/stack/pan/pan_main.cc index 88b433ed81..0b3cb55898 100644 --- a/system/stack/pan/pan_main.cc +++ b/system/stack/pan/pan_main.cc @@ -31,7 +31,6 @@ #include <cstdint> -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/bnep_api.h" #include "stack/include/bt_hdr.h" diff --git a/system/stack/pan/pan_utils.cc b/system/stack/pan/pan_utils.cc index eda89c4bed..eef9431004 100644 --- a/system/stack/pan/pan_utils.cc +++ b/system/stack/pan/pan_utils.cc @@ -30,7 +30,6 @@ #include <cstdint> #include "internal_include/bt_target.h" -#include "os/log.h" #include "stack/include/bt_types.h" #include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" diff --git a/system/stack/smp/smp_br_main.cc b/system/stack/smp/smp_br_main.cc index 12ee374011..20e6459a02 100644 --- a/system/stack/smp/smp_br_main.cc +++ b/system/stack/smp/smp_br_main.cc @@ -20,7 +20,6 @@ #include <bluetooth/log.h> -#include "os/log.h" #include "smp_int.h" #include "types/hci_role.h" diff --git a/system/stack/smp/smp_main.cc b/system/stack/smp/smp_main.cc index faaa2567cb..ead1d83028 100644 --- a/system/stack/smp/smp_main.cc +++ b/system/stack/smp/smp_main.cc @@ -20,7 +20,6 @@ #include <bluetooth/log.h> -#include "os/log.h" #include "smp_int.h" #include "stack/include/btm_log_history.h" diff --git a/system/stack/srvc/srvc_dis.cc b/system/stack/srvc/srvc_dis.cc index 58f6befd11..38751c653c 100644 --- a/system/stack/srvc/srvc_dis.cc +++ b/system/stack/srvc/srvc_dis.cc @@ -23,7 +23,6 @@ #include "gatt_api.h" #include "hardware/bt_gatt_types.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "srvc_dis_int.h" @@ -71,31 +70,6 @@ static tDIS_ATTR_MASK dis_uuid_to_attr(uint16_t uuid) { } /******************************************************************************* - * dis_valid_handle_range - * - * validate a handle to be a DIS attribute handle or not. - ******************************************************************************/ -bool dis_valid_handle_range(uint16_t /* handle */) { return false; } -/******************************************************************************* - * dis_write_attr_value - * - * Process write DIS attribute request. - ******************************************************************************/ -uint8_t dis_write_attr_value(tGATT_WRITE_REQ* /* p_data */, tGATT_STATUS* p_status) { - *p_status = GATT_WRITE_NOT_PERMIT; - return SRVC_ACT_RSP; -} -/******************************************************************************* - * DIS Attributes Database Server Request callback - ******************************************************************************/ -uint8_t dis_read_attr_value(uint8_t /* clcb_idx */, uint16_t /* handle */, - tGATT_VALUE* /* p_value */, bool /* is_long */, - tGATT_STATUS* p_status) { - *p_status = GATT_NOT_FOUND; - return SRVC_ACT_RSP; -} - -/******************************************************************************* * * Function dis_gatt_c_read_dis_value_cmpl * diff --git a/system/stack/srvc/srvc_dis_int.h b/system/stack/srvc/srvc_dis_int.h index dae3071bc1..607162a102 100644 --- a/system/stack/srvc/srvc_dis_int.h +++ b/system/stack/srvc/srvc_dis_int.h @@ -45,11 +45,6 @@ typedef struct { /* Global GATT data */ extern tDIS_CB dis_cb; -bool dis_valid_handle_range(uint16_t handle); -uint8_t dis_read_attr_value(uint8_t clcb_idx, uint16_t handle, tGATT_VALUE* p_value, bool is_long, - tGATT_STATUS* p_status); -uint8_t dis_write_attr_value(tGATT_WRITE_REQ* p_data, tGATT_STATUS* p_status); - void dis_c_cmpl_cback(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); diff --git a/system/stack/srvc/srvc_eng.cc b/system/stack/srvc/srvc_eng.cc index c1d877dd8e..92fb80cf71 100644 --- a/system/stack/srvc/srvc_eng.cc +++ b/system/stack/srvc/srvc_eng.cc @@ -27,11 +27,8 @@ #include "types/bluetooth/uuid.h" #include "types/raw_address.h" -using base::StringPrintf; using namespace bluetooth; -static void srvc_eng_s_request_cback(tCONN_ID conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type, - tGATTS_DATA* p_data); static void srvc_eng_connect_cback(tGATT_IF /* gatt_if */, const RawAddress& bda, tCONN_ID conn_id, bool connected, tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport); @@ -43,7 +40,7 @@ static tGATT_CBACK srvc_gatt_cback = { .p_cmpl_cb = srvc_eng_c_cmpl_cback, .p_disc_res_cb = nullptr, .p_disc_cmpl_cb = nullptr, - .p_req_cb = srvc_eng_s_request_cback, + .p_req_cb = nullptr, .p_enc_cmpl_cb = nullptr, .p_congestion_cb = nullptr, .p_phy_update_cb = nullptr, @@ -105,27 +102,6 @@ tSRVC_CLCB* srvc_eng_find_clcb_by_conn_id(tCONN_ID conn_id) { } /******************************************************************************* * - * Function srvc_eng_find_clcb_by_conn_id - * - * Description The function searches all LCBs with macthing connection ID. - * - * Returns Pointer to the found link conenction control block. - * - ******************************************************************************/ -static uint8_t srvc_eng_find_clcb_idx_by_conn_id(tCONN_ID conn_id) { - uint8_t i_clcb; - tSRVC_CLCB* p_clcb = NULL; - - for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++) { - if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) { - return i_clcb; - } - } - - return SRVC_MAX_APPS; -} -/******************************************************************************* - * * Function srvc_eng_clcb_alloc * * Description Allocate a GATT profile connection link control block @@ -175,105 +151,6 @@ static bool srvc_eng_clcb_dealloc(tCONN_ID conn_id) { } return false; } -/******************************************************************************* - * Service Engine Server Attributes Database Read/Read Blob Request process - ******************************************************************************/ -static uint8_t srvc_eng_process_read_req(uint8_t clcb_idx, tGATT_READ_REQ* p_data, - tGATTS_RSP* p_rsp, tGATT_STATUS* p_status) { - tGATT_STATUS status = GATT_NOT_FOUND; - uint8_t act = SRVC_ACT_RSP; - - if (p_data->is_long) { - p_rsp->attr_value.offset = p_data->offset; - } - - p_rsp->attr_value.handle = p_data->handle; - - if (dis_valid_handle_range(p_data->handle)) { - act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, - p_status); - } else { - *p_status = status; - } - return act; -} -/******************************************************************************* - * Service Engine Server Attributes Database write Request process - ******************************************************************************/ -static uint8_t srvc_eng_process_write_req(uint8_t /* clcb_idx */, tGATT_WRITE_REQ* p_data, - tGATTS_RSP* /* p_rsp */, tGATT_STATUS* p_status) { - uint8_t act = SRVC_ACT_RSP; - - if (dis_valid_handle_range(p_data->handle)) { - act = dis_write_attr_value(p_data, p_status); - } else { - *p_status = GATT_NOT_FOUND; - } - - return act; -} - -/******************************************************************************* - * - * Function srvc_eng_s_request_cback - * - * Description GATT DIS attribute access request callback. - * - * Returns void. - * - ******************************************************************************/ -static void srvc_eng_s_request_cback(tCONN_ID conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type, - tGATTS_DATA* p_data) { - tGATT_STATUS status = GATT_INVALID_PDU; - tGATTS_RSP rsp_msg; - uint8_t act = SRVC_ACT_IGNORE; - uint8_t clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id); - if (clcb_idx == SRVC_MAX_APPS) { - log::error("Can't find clcb, id:{}", conn_id); - return; - } - - log::verbose("srvc_eng_s_request_cback : recv type (0x{:02x})", type); - - memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); - - srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id; - - switch (type) { - case GATTS_REQ_TYPE_READ_CHARACTERISTIC: - case GATTS_REQ_TYPE_READ_DESCRIPTOR: - act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg, &status); - break; - - case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC: - case GATTS_REQ_TYPE_WRITE_DESCRIPTOR: - act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg, &status); - if (!p_data->write_req.need_rsp) { - act = SRVC_ACT_IGNORE; - } - break; - - case GATTS_REQ_TYPE_WRITE_EXEC: - log::verbose("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD"); - break; - - case GATTS_REQ_TYPE_MTU: - log::verbose("Get MTU exchange new mtu size: {}", p_data->mtu); - break; - - default: - log::verbose("Unknown/unexpected LE GAP ATT request: 0x{:02x}", type); - break; - } - - srvc_eng_cb.clcb[clcb_idx].trans_id = 0; - - if (act == SRVC_ACT_RSP) { - if (GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg) != GATT_SUCCESS) { - log::warn("Unable to send GATT server respond conn_id:{}", conn_id); - } - } -} /******************************************************************************* * @@ -381,7 +258,7 @@ void srvc_eng_release_channel(tCONN_ID conn_id) { ******************************************************************************/ tGATT_STATUS srvc_eng_init(void) { if (srvc_eng_cb.enabled) { - log::error("DIS already initialized"); + log::verbose("DIS already initialized"); } else { memset(&srvc_eng_cb, 0, sizeof(tSRVC_ENG_CB)); diff --git a/system/stack/test/a2dp/a2dp_sbc_unittest.cc b/system/stack/test/a2dp/a2dp_sbc_unittest.cc index 950a6100dd..cde2795cfc 100644 --- a/system/stack/test/a2dp/a2dp_sbc_unittest.cc +++ b/system/stack/test/a2dp/a2dp_sbc_unittest.cc @@ -24,7 +24,6 @@ #include <string> #include "common/time_util.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "stack/include/a2dp_sbc_decoder.h" #include "stack/include/a2dp_sbc_encoder.h" diff --git a/system/stack/test/a2dp/wav_reader.cc b/system/stack/test/a2dp/wav_reader.cc index 0dddd30e9f..b692f17014 100644 --- a/system/stack/test/a2dp/wav_reader.cc +++ b/system/stack/test/a2dp/wav_reader.cc @@ -22,7 +22,6 @@ #include <iterator> #include "os/files.h" -#include "os/log.h" namespace bluetooth { namespace testing { diff --git a/system/stack/test/btm_iso_test.cc b/system/stack/test/btm_iso_test.cc index 50a4948b34..3cb550b04d 100644 --- a/system/stack/test/btm_iso_test.cc +++ b/system/stack/test/btm_iso_test.cc @@ -2085,6 +2085,84 @@ TEST_F(IsoManagerTest, SendIsoDataCigValid) { } } +TEST_F(IsoManagerTest, SendReceiveIsoDataSequenceNumberCheck) { + IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id, + kDefaultCigParams); + + bluetooth::hci::iso_manager::cis_establish_params params; + for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) { + params.conn_pairs.push_back({handle, 1}); + } + IsoManager::GetInstance()->EstablishCis(params); + + for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) { + bluetooth::hci::iso_manager::iso_data_path_params path_params = kDefaultIsoDataPathParams; + path_params.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut; + IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params); + + constexpr uint8_t data_len = 108; + uint16_t seq_num = 0xFFFF; + + EXPECT_CALL(iso_interface_, HciSend) + .WillRepeatedly([handle, data_len, &seq_num](BT_HDR* p_msg) { + uint8_t* p = p_msg->data; + uint16_t msg_handle; + uint16_t iso_load_len; + + ASSERT_NE(p_msg, nullptr); + ASSERT_EQ(p_msg->len, + data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 12 : 8)); + + // Verify packet internals + STREAM_TO_UINT16(msg_handle, p); + ASSERT_EQ(msg_handle, handle); + + STREAM_TO_UINT16(iso_load_len, p); + ASSERT_EQ(iso_load_len, + data_len + ((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 8 : 4)); + + if (p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) { + STREAM_SKIP_UINT16(p); // skip ts LSB halfword + STREAM_SKIP_UINT16(p); // skip ts MSB halfword + } + // store the seq_nb + STREAM_TO_UINT16(seq_num, p); + + uint16_t msg_data_len; + STREAM_TO_UINT16(msg_data_len, p); + ASSERT_EQ(msg_data_len, data_len); + }) + .RetiresOnSaturation(); + + // Send Iso data and verify the sequence number + std::vector<uint8_t> data_vec(data_len, 0); + IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size()); + IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(), data_vec.size()); + ASSERT_NE(0xFFFF, seq_num); + + // Check the receiving iso packet + // EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(1); + EXPECT_CALL(*cig_callbacks_, + OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _)) + .WillOnce([](uint8_t /*evt_code*/, void* event) { + bluetooth::hci::iso_manager::cis_data_evt* cis_data_evt = + static_cast<bluetooth::hci::iso_manager::cis_data_evt*>(event); + // Make sure no event lost is reported due to seq_nb being shared between two + // directions + ASSERT_EQ(cis_data_evt->evt_lost, 0); + }); + + std::vector<uint8_t> dummy_msg(18); + uint8_t* p = dummy_msg.data(); + UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO); + UINT16_TO_STREAM(p, 10); // .len + UINT16_TO_STREAM(p, 0); // .offset + UINT16_TO_STREAM(p, 0); // .layer_specific + UINT16_TO_STREAM(p, handle); + IsoManager::GetInstance()->HandleIsoData(dummy_msg.data()); + } +} + TEST_F(IsoManagerTest, SendIsoDataBigValid) { IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id, kDefaultBigParams); diff --git a/system/stack/test/gatt_connection_manager_test.cc b/system/stack/test/connection_manager_test.cc index afe3fcba4e..cbb7b3ff35 100644 --- a/system/stack/test/gatt_connection_manager_test.cc +++ b/system/stack/test/connection_manager_test.cc @@ -1,3 +1,5 @@ +#include "stack/connection_manager/connection_manager.h" + #include <base/bind_helpers.h> #include <base/functional/bind.h> #include <base/functional/callback.h> @@ -11,7 +13,6 @@ #include "osi/test/alarm_mock.h" #include "security_device_record.h" #include "stack/btm/neighbor_inquiry.h" -#include "stack/gatt/connection_manager.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/stack/test/gatt/mock_gatt_utils_ref.cc b/system/stack/test/gatt/mock_gatt_utils_ref.cc index f79db0ac3d..2f392b3e90 100644 --- a/system/stack/test/gatt/mock_gatt_utils_ref.cc +++ b/system/stack/test/gatt/mock_gatt_utils_ref.cc @@ -22,7 +22,7 @@ #pragma GCC diagnostic ignored "-Wmissing-prototypes" #pragma GCC diagnostic ignored "-Wunused-parameter" -/** stack/gatt/connection_manager.cc */ +/** 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) { diff --git a/system/stack/test/stack_avctp_test.cc b/system/stack/test/stack_avctp_test.cc new file mode 100644 index 0000000000..17abac13c6 --- /dev/null +++ b/system/stack/test/stack_avctp_test.cc @@ -0,0 +1,128 @@ +/* + * 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 <bluetooth/log.h> +#include <gtest/gtest.h> +#include <unistd.h> + +#include "stack/include/avct_api.h" +#include "stack/include/bt_psm_types.h" +#include "test/fake/fake_osi.h" +#include "test/mock/mock_stack_l2cap_interface.h" + +using ::testing::_; +using ::testing::Args; +using ::testing::DoAll; +using ::testing::SaveArg; + +namespace { +constexpr uint16_t kRemoteCid = 0x0123; +const RawAddress kRawAddress = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); +} // namespace + +class StackAvctpTest : public ::testing::Test { +protected: + void SetUp() override { + fake_osi_ = std::make_unique<::test::fake::FakeOsi>(); + bluetooth::testing::stack::l2cap::set_interface(&mock_stack_l2cap_interface_); + EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_RegisterWithSecurity(_, _, _, _, _, _, _)) + .WillRepeatedly([this](unsigned short psm, const tL2CAP_APPL_INFO& cb, bool /* c */, + tL2CAP_ERTM_INFO* /*d*/, unsigned short /* e */, + unsigned short /* f */, unsigned short /* g */) { + this->callback_map_.insert(std::make_tuple(psm, cb)); + return psm; + }); + EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_DisconnectReq(_)).WillRepeatedly([]() { + return true; + }); + AVCT_Register(); + // Make sure we have a callback for both PSMs + ASSERT_EQ(2U, callback_map_.size()); + } + + void TearDown() override { + EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_Deregister(BT_PSM_AVCTP)); + EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_Deregister(BT_PSM_AVCTP_BROWSE)); + AVCT_Deregister(); + } + + std::map<uint16_t, tL2CAP_APPL_INFO> callback_map_; + bluetooth::testing::stack::l2cap::Mock mock_stack_l2cap_interface_; + std::unique_ptr<test::fake::FakeOsi> fake_osi_; + int fd_{STDOUT_FILENO}; +}; + +TEST_F(StackAvctpTest, AVCT_Dumpsys) { AVCT_Dumpsys(fd_); } + +TEST_F(StackAvctpTest, AVCT_CreateConn) { + EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_ConnectReqWithSecurity(_, _, _)) + .WillRepeatedly([](unsigned short /* psm */, const RawAddress /* bd_addr */, + uint16_t /* sec_level */) { return 0x1234; }); + + uint8_t handle; + tAVCT_CC cc = { + .p_ctrl_cback = [](uint8_t /* handle */, uint8_t /* event */, uint16_t /* result */, + const RawAddress* /* peer_addr */) {}, + .p_msg_cback = [](uint8_t /* handle */, uint8_t /* label */, uint8_t /* cr */, + BT_HDR* /* p_pkt */) {}, + .pid = 0x1234, + .role = AVCT_ROLE_INITIATOR, + .control = 1, + }; + ASSERT_EQ(AVCT_SUCCESS, AVCT_CreateConn(&handle, &cc, kRawAddress)); + ASSERT_EQ(AVCT_SUCCESS, AVCT_RemoveConn(handle)); +} + +TEST_F(StackAvctpTest, AVCT_CreateBrowse) { + EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_ConnectReqWithSecurity(_, _, _)) + .WillRepeatedly([](unsigned short /* psm */, const RawAddress /* bd_addr */, + uint16_t /* sec_level */) { return 0x1234; }); + + uint8_t handle; + tAVCT_CC cc = { + .p_ctrl_cback = [](uint8_t /* handle */, uint8_t /* event */, uint16_t /* result */, + const RawAddress* /* peer_addr */) {}, + .p_msg_cback = [](uint8_t /* handle */, uint8_t /* label */, uint8_t /* cr */, + BT_HDR* /* p_pkt */) {}, + .pid = 0x1234, + .role = AVCT_ROLE_INITIATOR, + .control = 1, + }; + ASSERT_EQ(AVCT_SUCCESS, AVCT_CreateConn(&handle, &cc, kRawAddress)); + ASSERT_EQ(AVCT_SUCCESS, AVCT_CreateBrowse(handle, AVCT_ROLE_INITIATOR)); + + ASSERT_EQ(AVCT_SUCCESS, AVCT_RemoveBrowse(handle)); + ASSERT_EQ(AVCT_SUCCESS, AVCT_RemoveConn(handle)); +} + +TEST_F(StackAvctpTest, AVCT_RemoteInitiatesControl) { + // AVCT Control + callback_map_[BT_PSM_AVCTP].pL2CA_ConnectInd_Cb(kRawAddress, kRemoteCid, BT_PSM_AVCTP, 0); + callback_map_[BT_PSM_AVCTP].pL2CA_ConnectCfm_Cb(kRemoteCid, tL2CAP_CONN::L2CAP_CONN_OK); +} + +TEST_F(StackAvctpTest, AVCT_RemoteInitiatesBrowse) { + // AVCT Control + callback_map_[BT_PSM_AVCTP].pL2CA_ConnectInd_Cb(kRawAddress, kRemoteCid, BT_PSM_AVCTP, 0); + callback_map_[BT_PSM_AVCTP].pL2CA_ConnectCfm_Cb(kRemoteCid, tL2CAP_CONN::L2CAP_CONN_OK); + + // AVCT Browse + callback_map_[BT_PSM_AVCTP_BROWSE].pL2CA_ConnectInd_Cb(kRawAddress, kRemoteCid, + BT_PSM_AVCTP_BROWSE, 0); + callback_map_[BT_PSM_AVCTP_BROWSE].pL2CA_ConnectCfm_Cb(kRemoteCid, tL2CAP_CONN::L2CAP_CONN_OK); + + AVCT_Dumpsys(fd_); +} diff --git a/system/stack/test/stack_l2cap_test.cc b/system/stack/test/stack_l2cap_test.cc index d2d19bf39e..ffe78055bc 100644 --- a/system/stack/test/stack_l2cap_test.cc +++ b/system/stack/test/stack_l2cap_test.cc @@ -287,7 +287,7 @@ TEST_F(StackL2capTest, bt_psm_text) { {BT_PSM_UPNP, "BT_PSM_UPNP"}, {BT_PSM_AVCTP, "BT_PSM_AVCTP"}, {BT_PSM_AVDTP, "BT_PSM_AVDTP"}, - {BT_PSM_AVCTP_13, "BT_PSM_AVCTP_13"}, + {BT_PSM_AVCTP_BROWSE, "BT_PSM_AVCTP_BROWSE"}, {BT_PSM_UDI_CP, "BT_PSM_UDI_CP"}, {BT_PSM_ATT, "BT_PSM_ATT"}, {BT_PSM_EATT, "BT_PSM_EATT"}, diff --git a/system/test/Android.bp b/system/test/Android.bp index a78ed4e8ef..d4a1a767eb 100644 --- a/system/test/Android.bp +++ b/system/test/Android.bp @@ -484,6 +484,13 @@ filegroup { } filegroup { + name: "TestMockStackConnMgr", + srcs: [ + "mock/mock_stack_connection_manager.cc", + ], +} + +filegroup { name: "TestMockStackEatt", srcs: [ "mock/mock_stack_eatt*.cc", diff --git a/system/test/common/jni_thread.cc b/system/test/common/jni_thread.cc index 984b2337c1..db1520d36b 100644 --- a/system/test/common/jni_thread.cc +++ b/system/test/common/jni_thread.cc @@ -21,8 +21,6 @@ #include <map> -#include "os/log.h" - // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/test/common/main_handler.cc b/system/test/common/main_handler.cc index 8728ab1cd8..c6e792c4dc 100644 --- a/system/test/common/main_handler.cc +++ b/system/test/common/main_handler.cc @@ -27,7 +27,6 @@ #include "common/message_loop_thread.h" #include "common/postable_context.h" #include "include/hardware/bluetooth.h" -#include "os/log.h" // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" diff --git a/system/test/headless/adapter/adapter.cc b/system/test/headless/adapter/adapter.cc index bbb3231047..cdf430d459 100644 --- a/system/test/headless/adapter/adapter.cc +++ b/system/test/headless/adapter/adapter.cc @@ -20,7 +20,6 @@ #include <bluetooth/log.h> -#include "gd/os/log.h" #include "test/headless/headless.h" #include "test/headless/interface.h" #include "test/headless/log.h" diff --git a/system/test/headless/bt_stack_info.cc b/system/test/headless/bt_stack_info.cc index ad00ba5c6b..300dbf62b7 100644 --- a/system/test/headless/bt_stack_info.cc +++ b/system/test/headless/bt_stack_info.cc @@ -21,7 +21,7 @@ #include "btif/include/btif_common.h" // do_in_jni_thread #include "btif/include/btif_hh.h" // DumpsysHid #include "main/shim/dumpsys.h" -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "stack/include/main_thread.h" #include "stack/include/pan_api.h" // PAN_Dumpsys #include "test/headless/log.h" diff --git a/system/test/headless/discovery/discovery.cc b/system/test/headless/discovery/discovery.cc index 5244eb893a..34c295188b 100644 --- a/system/test/headless/discovery/discovery.cc +++ b/system/test/headless/discovery/discovery.cc @@ -21,7 +21,6 @@ #include <future> #include "btif/include/btif_api.h" -#include "os/log.h" // android log only #include "stack/include/sdp_api.h" #include "test/headless/bt_property.h" #include "test/headless/get_options.h" diff --git a/system/test/headless/get_options.cc b/system/test/headless/get_options.cc index 3ad9fd48e5..fcab08d45d 100644 --- a/system/test/headless/get_options.cc +++ b/system/test/headless/get_options.cc @@ -23,7 +23,6 @@ #include <sstream> #include <string> -#include "os/log.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" diff --git a/system/test/headless/headless.cc b/system/test/headless/headless.cc index ebfcb041ec..5f0d820c7a 100644 --- a/system/test/headless/headless.cc +++ b/system/test/headless/headless.cc @@ -25,7 +25,6 @@ #include <map> #include <memory> -#include "gd/os/log.h" #include "include/hardware/bluetooth.h" #include "test/headless/bt_stack_info.h" #include "test/headless/interface.h" diff --git a/system/test/headless/interface.h b/system/test/headless/interface.h index f06df13a4c..11c314c8b7 100644 --- a/system/test/headless/interface.h +++ b/system/test/headless/interface.h @@ -21,7 +21,6 @@ #include <deque> #include <string> -#include "gd/os/log.h" #include "include/hardware/bluetooth.h" #include "macros.h" #include "test/headless/log.h" diff --git a/system/test/headless/log.cc b/system/test/headless/log.cc index 4714b98c2d..729db46475 100644 --- a/system/test/headless/log.cc +++ b/system/test/headless/log.cc @@ -14,8 +14,6 @@ * limitations under the License. */ -#include "os/log.h" - #include <chrono> #include <ctime> #include <string> diff --git a/system/test/headless/main.cc b/system/test/headless/main.cc index feba9c1909..313b0f1e71 100644 --- a/system/test/headless/main.cc +++ b/system/test/headless/main.cc @@ -25,7 +25,6 @@ #include <iostream> #include <unordered_map> -#include "os/log.h" // android log only #include "test/headless/adapter/adapter.h" #include "test/headless/connect/connect.h" #include "test/headless/discovery/discovery.h" diff --git a/system/test/headless/nop/nop.cc b/system/test/headless/nop/nop.cc index fcae19aa25..5383953608 100644 --- a/system/test/headless/nop/nop.cc +++ b/system/test/headless/nop/nop.cc @@ -20,7 +20,6 @@ #include <future> -#include "os/log.h" // android log only #include "stack/include/sdp_api.h" #include "test/headless/get_options.h" #include "test/headless/headless.h" diff --git a/system/test/headless/property.cc b/system/test/headless/property.cc index 65373f82f9..fe6e21f1ed 100644 --- a/system/test/headless/property.cc +++ b/system/test/headless/property.cc @@ -20,7 +20,6 @@ #include <map> -#include "gd/os/log.h" #include "include/hardware/bluetooth.h" #include "test/headless/log.h" diff --git a/system/test/headless/read/read.cc b/system/test/headless/read/read.cc index 08cf26d8fd..51e29448ac 100644 --- a/system/test/headless/read/read.cc +++ b/system/test/headless/read/read.cc @@ -18,7 +18,6 @@ #include "test/headless/read/read.h" -#include "os/log.h" // android log only #include "test/headless/get_options.h" #include "test/headless/headless.h" #include "test/headless/read/name.h" diff --git a/system/test/headless/scan/scan.cc b/system/test/headless/scan/scan.cc index d72b52236a..58c7bc9bcf 100644 --- a/system/test/headless/scan/scan.cc +++ b/system/test/headless/scan/scan.cc @@ -20,7 +20,6 @@ #include <bluetooth/log.h> -#include "os/log.h" #include "test/headless/get_options.h" #include "test/headless/headless.h" #include "test/headless/interface.h" diff --git a/system/test/headless/text.cc b/system/test/headless/text.cc index dc9303b982..fefc47780d 100644 --- a/system/test/headless/text.cc +++ b/system/test/headless/text.cc @@ -22,7 +22,6 @@ #include "include/hardware/bluetooth.h" #include "macros.h" -#include "os/log.h" std::string bt_conn_direction_text(const bt_conn_direction_t& direction) { switch (direction) { diff --git a/system/test/mock/mock_bta_av_api.h b/system/test/mock/mock_bta_av_api.h index f6319691c0..31fd804f67 100644 --- a/system/test/mock/mock_bta_av_api.h +++ b/system/test/mock/mock_bta_av_api.h @@ -33,7 +33,6 @@ // may need attention to prune from (or add to ) the inclusion set. #include "bta/av/bta_av_int.h" #include "btif/include/btif_av.h" -#include "os/log.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "stack/include/bt_hdr.h" diff --git a/system/test/mock/mock_stack_avct_api.cc b/system/test/mock/mock_stack_avct_api.cc index 42dae21043..2e88b66e84 100644 --- a/system/test/mock/mock_stack_avct_api.cc +++ b/system/test/mock/mock_stack_avct_api.cc @@ -24,7 +24,7 @@ #include "test/common/mock_functions.h" #include "types/raw_address.h" -uint16_t AVCT_CreateBrowse(uint8_t /* handle */, uint8_t /* role */) { +uint16_t AVCT_CreateBrowse(uint8_t /* handle */, tAVCT_ROLE /* role */) { inc_func_call_count(__func__); return 0; } @@ -56,3 +56,4 @@ uint16_t AVCT_RemoveConn(uint8_t /* handle */) { } void AVCT_Deregister(void) { inc_func_call_count(__func__); } void AVCT_Register() { inc_func_call_count(__func__); } +void AVCT_Dumpsys(int /* fd */) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_stack_avrc_api.cc b/system/test/mock/mock_stack_avrc_api.cc index 5409f75345..655690c7ec 100644 --- a/system/test/mock/mock_stack_avrc_api.cc +++ b/system/test/mock/mock_stack_avrc_api.cc @@ -25,9 +25,6 @@ #include "test/common/mock_functions.h" #include "types/raw_address.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - bool avrcp_absolute_volume_is_enabled() { inc_func_call_count(__func__); return true; @@ -58,7 +55,7 @@ uint16_t AVRC_Open(uint8_t* /* p_handle */, tAVRC_CONN_CB* /* p_ccb */, inc_func_call_count(__func__); return 0; } -uint16_t AVRC_OpenBrowse(uint8_t /* handle */, uint8_t /* conn_role */) { +uint16_t AVRC_OpenBrowse(uint8_t /* handle */, tAVCT_ROLE /* conn_role */) { inc_func_call_count(__func__); return 0; } @@ -79,7 +76,6 @@ uint16_t AVRC_PassRsp(uint8_t /* handle */, uint8_t /* label */, tAVRC_MSG_PASS* return 0; } void avrc_flush_cmd_q(uint8_t /* handle */) { inc_func_call_count(__func__); } -void avrc_process_timeout(void* /* data */) { inc_func_call_count(__func__); } void avrc_send_next_vendor_cmd(uint8_t /* handle */) { inc_func_call_count(__func__); } void avrc_start_cmd_timer(uint8_t /* handle */, uint8_t /* label */, uint8_t /* msg_mask */) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_stack_avrc_bld_tg.cc b/system/test/mock/mock_stack_avrc_bld_tg.cc index 6a1f126edd..7ff5e8fc26 100644 --- a/system/test/mock/mock_stack_avrc_bld_tg.cc +++ b/system/test/mock/mock_stack_avrc_bld_tg.cc @@ -24,15 +24,8 @@ #include "stack/include/bt_hdr.h" #include "test/common/mock_functions.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - tAVRC_STS AVRC_BldResponse(uint8_t /* handle */, tAVRC_RESPONSE* /* p_rsp */, BT_HDR** /* pp_pkt */) { inc_func_call_count(__func__); return 0; } -tAVRC_STS avrc_bld_group_navigation_rsp(uint16_t /* navi_id */, BT_HDR* /* p_pkt */) { - inc_func_call_count(__func__); - return 0; -} diff --git a/system/test/mock/mock_stack_avrc_pars.ct.cc b/system/test/mock/mock_stack_avrc_pars.ct.cc index 511231e11d..193f2f21b5 100644 --- a/system/test/mock/mock_stack_avrc_pars.ct.cc +++ b/system/test/mock/mock_stack_avrc_pars.ct.cc @@ -23,9 +23,6 @@ #include "avrc_defs.h" #include "test/common/mock_functions.h" -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* /* p_msg */, tAVRC_RESPONSE* /* p_result */, uint8_t* /* p_buf */, uint16_t* /* buf_len */) { inc_func_call_count(__func__); @@ -36,8 +33,3 @@ tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* /* p_msg */, tAVRC_RESPONSE* /* p_result inc_func_call_count(__func__); return 0; } -tAVRC_STS avrc_parse_notification_rsp(uint8_t* /* p_stream */, uint16_t /* len */, - tAVRC_REG_NOTIF_RSP* /* p_rsp */) { - inc_func_call_count(__func__); - return 0; -} diff --git a/system/test/mock/mock_stack_gatt_connection_manager.cc b/system/test/mock/mock_stack_connection_manager.cc index f0f33dddb5..97cd160854 100644 --- a/system/test/mock/mock_stack_gatt_connection_manager.cc +++ b/system/test/mock/mock_stack_connection_manager.cc @@ -21,12 +21,18 @@ #include <set> -#include "stack/gatt/connection_manager.h" +#include "stack/connection_manager/connection_manager.h" #include "test/common/mock_functions.h" #include "types/raw_address.h" using namespace connection_manager; +bool connection_manager::background_connect_targeted_announcement_add( + tAPP_ID /* app_id */, const RawAddress& /* address */) { + inc_func_call_count(__func__); + return false; +} + bool connection_manager::background_connect_add(uint8_t /* app_id */, const RawAddress& /* address */) { 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 c360878a6b..b8f3f4e227 100644 --- a/system/test/mock/mock_stack_l2cap_api.cc +++ b/system/test/mock/mock_stack_l2cap_api.cc @@ -37,7 +37,6 @@ namespace mock { namespace stack_l2cap_api { // Function state capture and return values, if needed -struct l2c_get_transport_from_fixed_cid l2c_get_transport_from_fixed_cid; struct L2CA_RegisterWithSecurity L2CA_RegisterWithSecurity; struct L2CA_Register L2CA_Register; struct L2CA_Deregister L2CA_Deregister; @@ -82,10 +81,6 @@ struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold; } // namespace test // Mocked functions, if any -tBT_TRANSPORT l2c_get_transport_from_fixed_cid(uint16_t fixed_cid) { - inc_func_call_count(__func__); - return test::mock::stack_l2cap_api::l2c_get_transport_from_fixed_cid(fixed_cid); -} uint16_t L2CA_RegisterWithSecurity(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, diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h index c2d162afd2..40d746ecd3 100644 --- a/system/test/mock/mock_stack_l2cap_api.h +++ b/system/test/mock/mock_stack_l2cap_api.h @@ -39,17 +39,6 @@ namespace test { namespace mock { namespace stack_l2cap_api { - -// Shared state between mocked functions and tests -// Name: l2c_get_transport_from_fixed_cid -// Params: uint16_t fixed_cid -// Returns: tBT_TRANSPORT -struct l2c_get_transport_from_fixed_cid { - std::function<tBT_TRANSPORT(uint16_t fixed_cid)> body{ - [](uint16_t /* fixed_cid */) { return BT_TRANSPORT_AUTO; }}; - tBT_TRANSPORT operator()(uint16_t fixed_cid) { return body(fixed_cid); } -}; -extern struct l2c_get_transport_from_fixed_cid l2c_get_transport_from_fixed_cid; // Name: L2CA_RegisterWithSecurity // Params: 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, diff --git a/system/test/mock/mock_stack_l2cap_ble.cc b/system/test/mock/mock_stack_l2cap_ble.cc index ee62576516..7dcd2f6bf0 100644 --- a/system/test/mock/mock_stack_l2cap_ble.cc +++ b/system/test/mock/mock_stack_l2cap_ble.cc @@ -58,7 +58,6 @@ struct l2cble_credit_based_conn_req l2cble_credit_based_conn_req; struct l2cble_credit_based_conn_res l2cble_credit_based_conn_res; struct l2cble_send_flow_control_credit l2cble_send_flow_control_credit; struct l2cble_send_peer_disc_req l2cble_send_peer_disc_req; -struct l2cble_sec_comp l2cble_sec_comp; struct l2ble_sec_access_req l2ble_sec_access_req; struct L2CA_AdjustConnectionIntervals L2CA_AdjustConnectionIntervals; struct L2CA_SetEcosystemBaseInterval L2CA_SetEcosystemBaseInterval; @@ -158,11 +157,6 @@ void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) { inc_func_call_count(__func__); test::mock::stack_l2cap_ble::l2cble_send_peer_disc_req(p_ccb); } -void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport, void* p_ref_data, - tBTM_STATUS status) { - inc_func_call_count(__func__); - test::mock::stack_l2cap_ble::l2cble_sec_comp(bda, transport, p_ref_data, status); -} tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm, bool is_originator, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) { diff --git a/system/test/mock/mock_stack_l2cap_ble.h b/system/test/mock/mock_stack_l2cap_ble.h index 6f13fed735..c5c3e45a1d 100644 --- a/system/test/mock/mock_stack_l2cap_ble.h +++ b/system/test/mock/mock_stack_l2cap_ble.h @@ -227,20 +227,6 @@ struct l2cble_send_peer_disc_req { void operator()(tL2C_CCB* p_ccb) { body(p_ccb); } }; extern struct l2cble_send_peer_disc_req l2cble_send_peer_disc_req; -// Name: l2cble_sec_comp -// Params: const RawAddress* bda, tBT_TRANSPORT transport, void* p_ref_data, -// tBTM_STATUS status Returns: void -struct l2cble_sec_comp { - std::function<void(const RawAddress* bda, tBT_TRANSPORT transport, void* p_ref_data, - tBTM_STATUS status)> - body{[](const RawAddress* /* bda */, tBT_TRANSPORT /* transport */, - void* /* p_ref_data */, tBTM_STATUS /* status */) {}}; - void operator()(const RawAddress* bda, tBT_TRANSPORT transport, void* p_ref_data, - tBTM_STATUS status) { - body(bda, transport, p_ref_data, status); - } -}; -extern struct l2cble_sec_comp l2cble_sec_comp; // Name: l2ble_sec_access_req // Params: const RawAddress& bd_addr, uint16_t psm, bool is_originator, // tL2CAP_SEC_CBACK* p_callback, void* p_ref_data Returns: tL2CAP_LE_RESULT_CODE diff --git a/system/test/mock/mock_stack_l2cap_link.cc b/system/test/mock/mock_stack_l2cap_link.cc index c0dea8c1fc..0c520ee594 100644 --- a/system/test/mock/mock_stack_l2cap_link.cc +++ b/system/test/mock/mock_stack_l2cap_link.cc @@ -22,17 +22,14 @@ #include "stack/include/bt_hdr.h" #include "stack/include/btm_status.h" +#include "stack/include/l2cap_acl_interface.h" +#include "stack/include/l2cap_controller_interface.h" +#include "stack/include/l2cap_hci_link_interface.h" +#include "stack/include/l2cap_security_interface.h" #include "stack/l2cap/l2c_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" - -BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* /* p_lcb */) { - inc_func_call_count(__func__); - return nullptr; -} bool l2c_link_hci_disc_comp(uint16_t /* handle */, tHCI_REASON /* reason */) { inc_func_call_count(__func__); return false; @@ -41,10 +38,6 @@ tBTM_STATUS l2cu_ConnectAclForSecurity(const RawAddress& /* bd_addr */) { inc_func_call_count(__func__); return tBTM_STATUS::BTM_SUCCESS; } -tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* /* p_lcb */) { - inc_func_call_count(__func__); - return nullptr; -} void l2c_OnHciModeChangeSendPendingPackets(RawAddress /* remote */) { inc_func_call_count(__func__); } @@ -64,12 +57,11 @@ void l2c_link_role_changed(const RawAddress* /* bd_addr */, tHCI_ROLE /* new_rol tHCI_STATUS /* hci_status */) { inc_func_call_count(__func__); } -void l2c_link_sec_comp(const RawAddress* /* p_bda */, tBT_TRANSPORT /* transport */, - void* /* p_ref_data */, uint8_t /* status */) { +void l2c_link_sec_comp(const RawAddress /* bda */, tBT_TRANSPORT /* transport */, + void* /* p_ref_data */, tBTM_STATUS /* status */) { inc_func_call_count(__func__); } -void l2c_link_segments_xmitted(BT_HDR* /* p_msg */) { inc_func_call_count(__func__); } void l2c_link_timeout(tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); } void l2c_packets_completed(uint16_t /* handle */, uint16_t /* num_sent */) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_stack_l2cap_utils.cc b/system/test/mock/mock_stack_l2cap_utils.cc index accdc72881..f485c111e4 100644 --- a/system/test/mock/mock_stack_l2cap_utils.cc +++ b/system/test/mock/mock_stack_l2cap_utils.cc @@ -29,11 +29,6 @@ // TODO(b/369381361) Enfore -Wmissing-prototypes #pragma GCC diagnostic ignored "-Wmissing-prototypes" -BT_HDR* l2cu_build_header(tL2C_LCB* /* p_lcb */, uint16_t /* len */, uint8_t /* cmd */, - uint8_t /* signal_id */) { - inc_func_call_count(__func__); - return nullptr; -} bool l2c_is_cmd_rejected(uint8_t /* cmd_code */, uint8_t /* signal_id */, tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); return false; @@ -113,15 +108,10 @@ tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t /* psm */) { inc_func_call_count(__func__); return nullptr; } -uint8_t l2cu_get_num_hi_priority(void) { - inc_func_call_count(__func__); - return 0; -} uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* /* p_ccb */, tL2CAP_CFG_INFO* /* p_cfg */) { inc_func_call_count(__func__); return 0; } -void l2cu_adj_id(tL2C_LCB* /* p_lcb */) { inc_func_call_count(__func__); } void l2cu_adjust_out_mps(tL2C_CCB* /* p_ccb */) { inc_func_call_count(__func__); } void l2cu_change_pri_ccb(tL2C_CCB* /* p_ccb */, tL2CAP_CHNL_PRIORITY /* priority */) { inc_func_call_count(__func__); diff --git a/system/test/mock/mock_stack_srvc_dis.cc b/system/test/mock/mock_stack_srvc_dis.cc index abd467c3a9..fc301ea0a1 100644 --- a/system/test/mock/mock_stack_srvc_dis.cc +++ b/system/test/mock/mock_stack_srvc_dis.cc @@ -38,20 +38,6 @@ bool dis_gatt_c_read_dis_req(uint16_t /* conn_id */) { inc_func_call_count(__func__); return false; } -bool dis_valid_handle_range(uint16_t /* handle */) { - inc_func_call_count(__func__); - return false; -} -uint8_t dis_read_attr_value(uint8_t /* clcb_idx */, uint16_t /* handle */, - tGATT_VALUE* /* p_value */, bool /* is_long */, - tGATT_STATUS* /* p_status */) { - inc_func_call_count(__func__); - return 0; -} -uint8_t dis_write_attr_value(tGATT_WRITE_REQ* /* p_data */, tGATT_STATUS* /* p_status */) { - inc_func_call_count(__func__); - return 0; -} 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/stub/osi.cc b/system/test/stub/osi.cc index fcfa858a91..17accc1794 100644 --- a/system/test/stub/osi.cc +++ b/system/test/stub/osi.cc @@ -20,6 +20,7 @@ #include "osi/include/osi.h" +#include <bluetooth/log.h> #include <sys/socket.h> #include <list> @@ -335,24 +336,70 @@ alarm_t* alarm_new_periodic(const char* name) { inc_func_call_count(__func__); return nullptr; } + +// Callback to last set alarm struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_; + +// Vector of previous osi alarms. Keep it for proper handling alarm_is_scheduler function +static std::vector<struct fake_osi_alarm_set_on_mloop> previous_fake_osi_alarms_; + bool alarm_is_scheduled(const alarm_t* alarm) { inc_func_call_count(__func__); - return fake_osi_alarm_set_on_mloop_.cb != nullptr; + + auto iter = + find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(), + [alarm](auto const& a) { + bluetooth::log::debug("iter: {} == {} ?", fmt::ptr(a.alarm), fmt::ptr(alarm)); + return a.alarm == alarm; + }); + if (iter != previous_fake_osi_alarms_.end()) { + return true; + } + + bluetooth::log::debug(" {} == {} ?", fmt::ptr(fake_osi_alarm_set_on_mloop_.alarm), + fmt::ptr(alarm)); + + return fake_osi_alarm_set_on_mloop_.alarm == alarm; } uint64_t alarm_get_remaining_ms(const alarm_t* alarm) { inc_func_call_count(__func__); return 0; } + +static void fake_osi_alarm_clear(alarm_t* alarm) { + if (alarm != nullptr) { + auto iter = find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(), + [alarm](auto const& a) { return a.alarm == alarm; }); + if (iter != previous_fake_osi_alarms_.end()) { + bluetooth::log::debug(" clearing alarm {} ", fmt::ptr(iter->alarm)); + previous_fake_osi_alarms_.erase(iter); + return; + } + } + + if (fake_osi_alarm_set_on_mloop_.alarm == alarm || alarm == nullptr) { + bluetooth::log::debug(" clearing alarm {} ", fmt::ptr(alarm)); + fake_osi_alarm_set_on_mloop_.alarm = nullptr; + fake_osi_alarm_set_on_mloop_.interval_ms = 0; + fake_osi_alarm_set_on_mloop_.cb = nullptr; + fake_osi_alarm_set_on_mloop_.data = nullptr; + } +} + void alarm_cancel(alarm_t* alarm) { inc_func_call_count(__func__); - fake_osi_alarm_set_on_mloop_.interval_ms = 0; - fake_osi_alarm_set_on_mloop_.cb = nullptr; - fake_osi_alarm_set_on_mloop_.data = nullptr; + fake_osi_alarm_clear(alarm); +} + +void alarm_cleanup(void) { + previous_fake_osi_alarms_.clear(); + fake_osi_alarm_clear(nullptr); + + inc_func_call_count(__func__); } -void alarm_cleanup(void) { inc_func_call_count(__func__); } void alarm_debug_dump(int fd) { inc_func_call_count(__func__); } void alarm_free(alarm_t* alarm) { + fake_osi_alarm_clear(alarm); uint8_t* ptr = (uint8_t*)alarm; delete[] ptr; inc_func_call_count(__func__); @@ -363,6 +410,14 @@ void alarm_set(alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb, void* void alarm_set_on_mloop(alarm_t* alarm, uint64_t interval_ms, alarm_callback_t cb, void* data) { inc_func_call_count(__func__); + + if (fake_osi_alarm_set_on_mloop_.alarm != nullptr) { + bluetooth::log::info("Queuing alarm {}", fmt::ptr(fake_osi_alarm_set_on_mloop_.alarm)); + previous_fake_osi_alarms_.push_back(fake_osi_alarm_set_on_mloop_); + } + + bluetooth::log::info("Adding alarm {}", fmt::ptr(alarm)); + fake_osi_alarm_set_on_mloop_.alarm = alarm; fake_osi_alarm_set_on_mloop_.interval_ms = interval_ms; fake_osi_alarm_set_on_mloop_.cb = cb; fake_osi_alarm_set_on_mloop_.data = data; diff --git a/system/udrv/ulinux/uipc.cc b/system/udrv/ulinux/uipc.cc index 464e02b7f1..d0d7de0fbb 100644 --- a/system/udrv/ulinux/uipc.cc +++ b/system/udrv/ulinux/uipc.cc @@ -44,7 +44,6 @@ #include <cerrno> #include <mutex> -#include "os/log.h" #include "osi/include/osi.h" #include "osi/include/socket_utils/sockets.h" diff --git a/tools/rootcanal/packets/hci_packets.pdl b/tools/rootcanal/packets/hci_packets.pdl index ec34b4da0f..db7c51d294 100644 --- a/tools/rootcanal/packets/hci_packets.pdl +++ b/tools/rootcanal/packets/hci_packets.pdl @@ -749,6 +749,7 @@ enum EventCode : 8 { REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D, LE_META_EVENT = 0x3e, NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48, + AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED = 0x57, ENCRYPTION_CHANGE_V2 = 0x59, VENDOR_SPECIFIC = 0xFF, } @@ -5134,6 +5135,11 @@ packet NumberOfCompletedDataBlocks : Event (event_code = NUMBER_OF_COMPLETED_DAT _payload_, // placeholder (unimplemented) } +packet AuthenticatedPayloadTimeoutExpired : Event (event_code = AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED) { + connection_handle : 12, + _reserved_ : 4, +} + // LE Events packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) { status : ErrorCode, |